From b52c0df46ca4b16cfdaf48749971b0d26ca74395 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 9 Dec 2017 18:56:52 +0000 Subject: [PATCH] Import llvm-toolchain-5.0_5.0.1.orig-lldb.tar.bz2 [dgit import orig llvm-toolchain-5.0_5.0.1.orig-lldb.tar.bz2] --- .arcconfig | 4 + .clang-format | 1 + .gitignore | 59 + CMakeLists.txt | 100 + CODE_OWNERS.txt | 55 + INSTALL.txt | 18 + LICENSE.TXT | 38 + cmake/LLDBDependencies.cmake | 52 + cmake/XcodeHeaderGenerator/CMakeLists.txt | 14 + cmake/modules/AddLLDB.cmake | 163 + cmake/modules/EmbedAppleVersion.cmake | 11 + cmake/modules/LLDBConfig.cmake | 415 + cmake/modules/LLDBGenerateConfig.cmake | 44 + cmake/modules/LLDBStandalone.cmake | 135 + docs/CMakeLists.txt | 41 + docs/building-with-debug-llvm.txt | 50 + docs/code-signing.txt | 61 + docs/doxygen.cfg.in | 1631 ++ docs/doxygen.footer | 13 + docs/doxygen.header | 9 + docs/doxygen.intro | 19 + docs/lldb-for-gdb-users.txt | 488 + docs/lldb-gdb-remote.txt | 1915 ++ docs/lldb.1 | 154 + docs/structured_data/DarwinLog.md | 160 + docs/structured_data/StructuredDataPlugins.md | 136 + ...gsCommandTestCase.test_set_output_path.log | 43 + docs/testsuite/a-detailed-walkthrough.txt | 309 + docs/testsuite/best-practices.txt | 93 + examples/customization/bin-utils/.lldbinit | 5 + examples/customization/bin-utils/README | 36 + examples/customization/bin-utils/binutils.py | 125 + examples/customization/import-python/README | 40 + .../customization/import-python/importcmd.py | 38 + .../customization/pwd-cd-and-system/.lldbinit | 7 + .../customization/pwd-cd-and-system/README | 41 + .../customization/pwd-cd-and-system/utils.py | 58 + examples/darwin/heap_find/heap.py | 1522 ++ examples/darwin/heap_find/heap/Makefile | 33 + examples/darwin/heap_find/heap/heap_find.cpp | 911 + examples/functions/Makefile | 18 + examples/functions/main.cpp | 346 + .../darwin/fd_interposing/FDInterposing.cpp | 985 ++ .../darwin/fd_interposing/Makefile | 7 + examples/lookup/Makefile | 17 + examples/lookup/main.cpp | 222 + examples/plugins/commands/fooplugin.cpp | 47 + examples/python/cmdtemplate.py | 112 + examples/python/crashlog.py | 1015 ++ examples/python/delta.py | 134 + examples/python/diagnose_nsstring.py | 183 + examples/python/diagnose_unwind.py | 313 + examples/python/dict_utils.py | 62 + examples/python/disasm-stress-test.py | 230 + examples/python/disasm.py | 126 + examples/python/disassembly_mode.py | 48 + examples/python/file_extract.py | 226 + examples/python/gdb_disassemble.py | 26 + examples/python/gdbremote.py | 1558 ++ examples/python/globals.py | 106 + examples/python/jump.py | 196 + examples/python/lldb_module_utils.py | 78 + examples/python/lldbtk.py | 613 + examples/python/mach_o.py | 1845 ++ examples/python/memory.py | 276 + examples/python/operating_system.py | 231 + examples/python/performance.py | 392 + examples/python/process_events.py | 417 + examples/python/pytracer.py | 360 + examples/python/sbvalue.py | 268 + examples/python/scripted_step.py | 244 + examples/python/shadow.py | 58 + examples/python/sources.py | 31 + examples/python/stacks.py | 69 + examples/python/symbolication.py | 727 + examples/python/types.py | 356 + .../python/x86_64_linux_target_definition.py | 775 + .../python/x86_64_qemu_target_definition.py | 773 + examples/python/x86_64_target_definition.py | 778 + examples/scripting/dictionary.c | 173 + examples/scripting/tree_utils.py | 118 + examples/summaries/cocoa/CFArray.py | 233 + examples/summaries/cocoa/CFBag.py | 163 + examples/summaries/cocoa/CFBinaryHeap.py | 161 + examples/summaries/cocoa/CFBitVector.py | 206 + examples/summaries/cocoa/CFDictionary.py | 263 + examples/summaries/cocoa/CFString.py | 351 + examples/summaries/cocoa/Class.py | 22 + examples/summaries/cocoa/Logger.py | 133 + examples/summaries/cocoa/NSBundle.py | 145 + examples/summaries/cocoa/NSData.py | 182 + examples/summaries/cocoa/NSDate.py | 307 + examples/summaries/cocoa/NSException.py | 134 + examples/summaries/cocoa/NSIndexSet.py | 176 + examples/summaries/cocoa/NSMachPort.py | 141 + examples/summaries/cocoa/NSNotification.py | 126 + examples/summaries/cocoa/NSNumber.py | 269 + examples/summaries/cocoa/NSSet.py | 289 + examples/summaries/cocoa/NSURL.py | 153 + examples/summaries/cocoa/Selector.py | 19 + examples/summaries/cocoa/attrib_fromdict.py | 42 + examples/summaries/cocoa/cache.py | 36 + examples/summaries/cocoa/metrics.py | 112 + examples/summaries/cocoa/objc_runtime.py | 901 + examples/summaries/essentials | 5 + examples/summaries/lldb | 28 + examples/summaries/objc.py | 19 + examples/summaries/pysummary.py | 24 + examples/summaries/sp_cp.py | 84 + examples/summaries/synth.py | 66 + examples/summaries/unicode_strings.py | 53 + examples/synthetic/bitfield/example.py | 123 + examples/synthetic/bitfield/program.cpp | 56 + examples/synthetic/gnu_libstdcpp.py | 480 + examples/synthetic/libcxx.py | 869 + examples/synthetic/unordered_multi.py | 124 + examples/test/.lldb-loggings | 20 + examples/test/.lldb-pre-post-flight | 12 + examples/test/.lldb-pre-post-flight.bad | 8 + examples/test/.lldbtest-config | 6 + examples/test/.lldbtest-config2 | 19 + examples/test/lldbtest-stderr | 39 + examples/test/lldbtest-stdout | 0 ...eakpointCommandTestCase.test_with_dsym.txt | 55 + ...akpointCommandTestCase.test_with_dwarf.txt | 55 + examples/test/usage-config | 10 + examples/test/usage-lldb-loggings | 125 + examples/test/usage-pre-post-flight | 65 + include/lldb/API/LLDB.h | 82 + include/lldb/API/SBAddress.h | 126 + include/lldb/API/SBAttachInfo.h | 190 + include/lldb/API/SBBlock.h | 96 + include/lldb/API/SBBreakpoint.h | 176 + include/lldb/API/SBBreakpointLocation.h | 88 + include/lldb/API/SBBroadcaster.h | 83 + include/lldb/API/SBCommandInterpreter.h | 284 + include/lldb/API/SBCommandReturnObject.h | 113 + include/lldb/API/SBCommunication.h | 82 + include/lldb/API/SBCompileUnit.h | 96 + include/lldb/API/SBData.h | 156 + include/lldb/API/SBDebugger.h | 273 + include/lldb/API/SBDeclaration.h | 70 + include/lldb/API/SBDefines.h | 103 + include/lldb/API/SBError.h | 89 + include/lldb/API/SBEvent.h | 86 + include/lldb/API/SBExecutionContext.h | 66 + include/lldb/API/SBExpressionOptions.h | 115 + include/lldb/API/SBFileSpec.h | 89 + include/lldb/API/SBFileSpecList.h | 58 + include/lldb/API/SBFrame.h | 200 + include/lldb/API/SBFunction.h | 81 + include/lldb/API/SBHostOS.h | 45 + include/lldb/API/SBInstruction.h | 87 + include/lldb/API/SBInstructionList.h | 67 + include/lldb/API/SBLanguageRuntime.h | 26 + include/lldb/API/SBLaunchInfo.h | 153 + include/lldb/API/SBLineEntry.h | 77 + include/lldb/API/SBListener.h | 107 + include/lldb/API/SBMemoryRegionInfo.h | 112 + include/lldb/API/SBMemoryRegionInfoList.h | 50 + include/lldb/API/SBModule.h | 316 + include/lldb/API/SBModuleSpec.h | 125 + include/lldb/API/SBPlatform.h | 167 + include/lldb/API/SBProcess.h | 406 + include/lldb/API/SBQueue.h | 72 + include/lldb/API/SBQueueItem.h | 48 + include/lldb/API/SBSection.h | 104 + include/lldb/API/SBSourceManager.h | 50 + include/lldb/API/SBStream.h | 104 + include/lldb/API/SBStringList.h | 62 + include/lldb/API/SBStructuredData.h | 106 + include/lldb/API/SBSymbol.h | 89 + include/lldb/API/SBSymbolContext.h | 82 + include/lldb/API/SBSymbolContextList.h | 57 + include/lldb/API/SBTarget.h | 847 + include/lldb/API/SBThread.h | 220 + include/lldb/API/SBThreadCollection.h | 56 + include/lldb/API/SBThreadPlan.h | 115 + include/lldb/API/SBTrace.h | 123 + include/lldb/API/SBTraceOptions.h | 58 + include/lldb/API/SBType.h | 255 + include/lldb/API/SBTypeCategory.h | 133 + include/lldb/API/SBTypeEnumMember.h | 80 + include/lldb/API/SBTypeFilter.h | 73 + include/lldb/API/SBTypeFormat.h | 77 + include/lldb/API/SBTypeNameSpecifier.h | 64 + include/lldb/API/SBTypeSummary.h | 136 + include/lldb/API/SBTypeSynthetic.h | 83 + include/lldb/API/SBUnixSignals.h | 70 + include/lldb/API/SBValue.h | 446 + include/lldb/API/SBValueList.h | 74 + include/lldb/API/SBVariablesOptions.h | 77 + include/lldb/API/SBWatchpoint.h | 80 + include/lldb/API/SystemInitializerFull.h | 38 + include/lldb/Breakpoint/Breakpoint.h | 763 + include/lldb/Breakpoint/BreakpointID.h | 111 + include/lldb/Breakpoint/BreakpointIDList.h | 79 + include/lldb/Breakpoint/BreakpointList.h | 222 + include/lldb/Breakpoint/BreakpointLocation.h | 429 + .../Breakpoint/BreakpointLocationCollection.h | 213 + .../lldb/Breakpoint/BreakpointLocationList.h | 267 + include/lldb/Breakpoint/BreakpointOptions.h | 407 + include/lldb/Breakpoint/BreakpointResolver.h | 257 + .../Breakpoint/BreakpointResolverAddress.h | 85 + .../Breakpoint/BreakpointResolverFileLine.h | 82 + .../Breakpoint/BreakpointResolverFileRegex.h | 85 + .../lldb/Breakpoint/BreakpointResolverName.h | 99 + include/lldb/Breakpoint/BreakpointSite.h | 287 + include/lldb/Breakpoint/BreakpointSiteList.h | 207 + include/lldb/Breakpoint/Stoppoint.h | 56 + .../Breakpoint/StoppointCallbackContext.h | 63 + include/lldb/Breakpoint/StoppointLocation.h | 101 + include/lldb/Breakpoint/Watchpoint.h | 236 + include/lldb/Breakpoint/WatchpointList.h | 253 + include/lldb/Breakpoint/WatchpointOptions.h | 246 + include/lldb/Core/Address.h | 581 + include/lldb/Core/AddressRange.h | 289 + include/lldb/Core/AddressResolver.h | 74 + include/lldb/Core/AddressResolverFileLine.h | 67 + include/lldb/Core/AddressResolverName.h | 74 + include/lldb/Core/ArchSpec.h | 665 + include/lldb/Core/Broadcaster.h | 607 + include/lldb/Core/ClangForward.h | 139 + include/lldb/Core/Communication.h | 416 + include/lldb/Core/Debugger.h | 430 + include/lldb/Core/Disassembler.h | 559 + include/lldb/Core/DumpDataExtractor.h | 95 + include/lldb/Core/EmulateInstruction.h | 535 + include/lldb/Core/Event.h | 276 + include/lldb/Core/FileLineResolver.h | 75 + include/lldb/Core/FileSpecList.h | 229 + include/lldb/Core/FormatEntity.h | 236 + include/lldb/Core/IOHandler.h | 608 + include/lldb/Core/IOStreamMacros.h | 42 + include/lldb/Core/Listener.h | 161 + include/lldb/Core/LoadedModuleInfoList.h | 119 + include/lldb/Core/Mangled.h | 317 + include/lldb/Core/MappedHash.h | 483 + include/lldb/Core/Module.h | 1220 ++ include/lldb/Core/ModuleChild.h | 85 + include/lldb/Core/ModuleList.h | 597 + include/lldb/Core/ModuleSpec.h | 425 + include/lldb/Core/Opcode.h | 279 + include/lldb/Core/PluginInterface.h | 32 + include/lldb/Core/PluginManager.h | 531 + include/lldb/Core/RangeMap.h | 1224 ++ include/lldb/Core/RegisterValue.h | 286 + include/lldb/Core/STLUtils.h | 85 + include/lldb/Core/Scalar.h | 380 + include/lldb/Core/SearchFilter.h | 531 + include/lldb/Core/Section.h | 287 + include/lldb/Core/SourceManager.h | 184 + include/lldb/Core/State.h | 85 + include/lldb/Core/StreamAsynchronousIO.h | 43 + include/lldb/Core/StreamBuffer.h | 56 + include/lldb/Core/StreamFile.h | 63 + include/lldb/Core/StructuredDataImpl.h | 156 + include/lldb/Core/ThreadSafeDenseMap.h | 70 + include/lldb/Core/ThreadSafeDenseSet.h | 60 + include/lldb/Core/ThreadSafeSTLMap.h | 137 + include/lldb/Core/ThreadSafeSTLVector.h | 81 + include/lldb/Core/ThreadSafeValue.h | 69 + include/lldb/Core/UniqueCStringMap.h | 273 + include/lldb/Core/UserSettingsController.h | 105 + include/lldb/Core/Value.h | 271 + include/lldb/Core/ValueObject.h | 1087 ++ include/lldb/Core/ValueObjectCast.h | 71 + include/lldb/Core/ValueObjectChild.h | 99 + include/lldb/Core/ValueObjectConstResult.h | 163 + .../lldb/Core/ValueObjectConstResultCast.h | 77 + .../lldb/Core/ValueObjectConstResultChild.h | 84 + .../lldb/Core/ValueObjectConstResultImpl.h | 88 + include/lldb/Core/ValueObjectDynamicValue.h | 145 + include/lldb/Core/ValueObjectList.h | 79 + include/lldb/Core/ValueObjectMemory.h | 86 + include/lldb/Core/ValueObjectRegister.h | 191 + .../lldb/Core/ValueObjectSyntheticFilter.h | 178 + include/lldb/Core/ValueObjectVariable.h | 103 + include/lldb/Core/dwarf.h | 85 + .../lldb/DataFormatters/CXXFunctionPointer.h | 22 + .../lldb/DataFormatters/DataVisualization.h | 146 + .../DataFormatters/DumpValueObjectOptions.h | 165 + include/lldb/DataFormatters/FormatCache.h | 112 + include/lldb/DataFormatters/FormatClasses.h | 177 + include/lldb/DataFormatters/FormatManager.h | 270 + .../lldb/DataFormatters/FormattersContainer.h | 350 + .../lldb/DataFormatters/FormattersHelpers.h | 194 + .../lldb/DataFormatters/LanguageCategory.h | 80 + include/lldb/DataFormatters/StringPrinter.h | 348 + include/lldb/DataFormatters/TypeCategory.h | 452 + include/lldb/DataFormatters/TypeCategoryMap.h | 125 + include/lldb/DataFormatters/TypeFormat.h | 223 + include/lldb/DataFormatters/TypeSummary.h | 403 + include/lldb/DataFormatters/TypeSynthetic.h | 453 + include/lldb/DataFormatters/TypeValidator.h | 207 + .../lldb/DataFormatters/ValueObjectPrinter.h | 166 + include/lldb/DataFormatters/VectorIterator.h | 45 + include/lldb/DataFormatters/VectorType.h | 25 + include/lldb/Expression/DWARFExpression.h | 444 + include/lldb/Expression/DiagnosticManager.h | 166 + include/lldb/Expression/Expression.h | 129 + include/lldb/Expression/ExpressionParser.h | 125 + .../lldb/Expression/ExpressionSourceCode.h | 63 + .../Expression/ExpressionTypeSystemHelper.h | 50 + include/lldb/Expression/ExpressionVariable.h | 268 + include/lldb/Expression/FunctionCaller.h | 391 + include/lldb/Expression/IRDynamicChecks.h | 170 + include/lldb/Expression/IRExecutionUnit.h | 437 + include/lldb/Expression/IRInterpreter.h | 58 + include/lldb/Expression/IRMemoryMap.h | 139 + include/lldb/Expression/LLVMUserExpression.h | 138 + include/lldb/Expression/Materializer.h | 144 + include/lldb/Expression/REPL.h | 176 + include/lldb/Expression/UserExpression.h | 314 + include/lldb/Expression/UtilityFunction.h | 143 + include/lldb/Host/Config.h | 31 + include/lldb/Host/Config.h.cmake | 27 + include/lldb/Host/ConnectionFileDescriptor.h | 15 + include/lldb/Host/Debug.h | 160 + include/lldb/Host/Editline.h | 374 + include/lldb/Host/File.h | 489 + include/lldb/Host/FileCache.h | 47 + include/lldb/Host/FileSystem.h | 42 + include/lldb/Host/Host.h | 256 + include/lldb/Host/HostGetOpt.h | 24 + include/lldb/Host/HostInfo.h | 71 + include/lldb/Host/HostInfoBase.h | 100 + include/lldb/Host/HostNativeProcess.h | 25 + include/lldb/Host/HostNativeProcessBase.h | 48 + include/lldb/Host/HostNativeThread.h | 23 + include/lldb/Host/HostNativeThreadBase.h | 52 + include/lldb/Host/HostNativeThreadForward.h | 26 + include/lldb/Host/HostProcess.h | 60 + include/lldb/Host/HostThread.h | 54 + include/lldb/Host/LockFile.h | 25 + include/lldb/Host/LockFileBase.h | 57 + include/lldb/Host/MainLoop.h | 112 + include/lldb/Host/MainLoopBase.h | 93 + include/lldb/Host/MonitoringProcessLauncher.h | 36 + include/lldb/Host/OptionParser.h | 51 + include/lldb/Host/Pipe.h | 25 + include/lldb/Host/PipeBase.h | 65 + include/lldb/Host/PosixApi.h | 23 + include/lldb/Host/Predicate.h | 524 + include/lldb/Host/ProcessLauncher.h | 27 + include/lldb/Host/ProcessRunLock.h | 92 + include/lldb/Host/PseudoTerminal.h | 252 + include/lldb/Host/Socket.h | 126 + include/lldb/Host/SocketAddress.h | 236 + include/lldb/Host/StringConvert.h | 47 + include/lldb/Host/Symbols.h | 66 + include/lldb/Host/Terminal.h | 218 + include/lldb/Host/ThreadLauncher.h | 44 + include/lldb/Host/Time.h | 26 + include/lldb/Host/XML.h | 191 + include/lldb/Host/android/HostInfoAndroid.h | 33 + include/lldb/Host/common/GetOptInc.h | 52 + include/lldb/Host/common/NativeBreakpoint.h | 56 + .../lldb/Host/common/NativeBreakpointList.h | 60 + .../lldb/Host/common/NativeProcessProtocol.h | 476 + .../lldb/Host/common/NativeRegisterContext.h | 201 + .../lldb/Host/common/NativeThreadProtocol.h | 72 + .../lldb/Host/common/NativeWatchpointList.h | 42 + include/lldb/Host/common/SoftwareBreakpoint.h | 53 + include/lldb/Host/common/TCPSocket.h | 59 + include/lldb/Host/common/UDPSocket.h | 35 + include/lldb/Host/freebsd/HostInfoFreeBSD.h | 27 + include/lldb/Host/linux/AbstractSocket.h | 26 + include/lldb/Host/linux/HostInfoLinux.h | 48 + include/lldb/Host/linux/Ptrace.h | 57 + include/lldb/Host/linux/Support.h | 30 + include/lldb/Host/linux/Uio.h | 24 + include/lldb/Host/macosx/HostInfoMacOSX.h | 46 + include/lldb/Host/macosx/HostThreadMacOSX.h | 29 + include/lldb/Host/netbsd/HostInfoNetBSD.h | 27 + include/lldb/Host/openbsd/HostInfoOpenBSD.h | 27 + .../posix/ConnectionFileDescriptorPosix.h | 128 + include/lldb/Host/posix/DomainSocket.h | 35 + include/lldb/Host/posix/Fcntl.h | 25 + include/lldb/Host/posix/HostInfoPosix.h | 46 + include/lldb/Host/posix/HostProcessPosix.h | 46 + include/lldb/Host/posix/HostThreadPosix.h | 33 + include/lldb/Host/posix/LockFilePosix.h | 36 + include/lldb/Host/posix/PipePosix.h | 76 + .../Host/posix/ProcessLauncherPosixFork.h | 25 + include/lldb/Host/windows/AutoHandle.h | 37 + .../windows/ConnectionGenericFileWindows.h | 64 + include/lldb/Host/windows/HostInfoWindows.h | 49 + .../lldb/Host/windows/HostProcessWindows.h | 46 + include/lldb/Host/windows/HostThreadWindows.h | 40 + include/lldb/Host/windows/LockFileWindows.h | 42 + include/lldb/Host/windows/PipeWindows.h | 81 + include/lldb/Host/windows/PosixApi.h | 105 + .../Host/windows/ProcessLauncherWindows.h | 30 + include/lldb/Host/windows/editlinewin.h | 116 + include/lldb/Host/windows/windows.h | 31 + .../lldb/Initialization/SystemInitializer.h | 24 + .../Initialization/SystemInitializerCommon.h | 37 + .../Initialization/SystemLifetimeManager.h | 41 + include/lldb/Interpreter/Args.h | 479 + include/lldb/Interpreter/CommandAlias.h | 94 + include/lldb/Interpreter/CommandCompletions.h | 259 + include/lldb/Interpreter/CommandHistory.h | 63 + include/lldb/Interpreter/CommandInterpreter.h | 558 + include/lldb/Interpreter/CommandObject.h | 502 + .../lldb/Interpreter/CommandObjectMultiword.h | 149 + .../Interpreter/CommandObjectRegexCommand.h | 68 + .../Interpreter/CommandOptionValidators.h | 33 + .../lldb/Interpreter/CommandReturnObject.h | 182 + .../Interpreter/OptionGroupArchitecture.h | 52 + include/lldb/Interpreter/OptionGroupBoolean.h | 58 + include/lldb/Interpreter/OptionGroupFile.h | 90 + include/lldb/Interpreter/OptionGroupFormat.h | 88 + .../lldb/Interpreter/OptionGroupOutputFile.h | 55 + .../lldb/Interpreter/OptionGroupPlatform.h | 83 + include/lldb/Interpreter/OptionGroupString.h | 55 + include/lldb/Interpreter/OptionGroupUInt64.h | 56 + include/lldb/Interpreter/OptionGroupUUID.h | 48 + .../OptionGroupValueObjectDisplay.h | 65 + .../lldb/Interpreter/OptionGroupVariable.h | 54 + .../lldb/Interpreter/OptionGroupWatchpoint.h | 61 + include/lldb/Interpreter/OptionValue.h | 350 + include/lldb/Interpreter/OptionValueArch.h | 93 + include/lldb/Interpreter/OptionValueArgs.h | 36 + include/lldb/Interpreter/OptionValueArray.h | 137 + include/lldb/Interpreter/OptionValueBoolean.h | 100 + include/lldb/Interpreter/OptionValueChar.h | 80 + .../lldb/Interpreter/OptionValueDictionary.h | 93 + .../lldb/Interpreter/OptionValueEnumeration.h | 93 + .../lldb/Interpreter/OptionValueFileSpec.h | 95 + .../Interpreter/OptionValueFileSpecList.h | 73 + include/lldb/Interpreter/OptionValueFormat.h | 75 + .../Interpreter/OptionValueFormatEntity.h | 77 + .../lldb/Interpreter/OptionValueLanguage.h | 78 + .../Interpreter/OptionValuePathMappings.h | 70 + .../lldb/Interpreter/OptionValueProperties.h | 235 + include/lldb/Interpreter/OptionValueRegex.h | 75 + include/lldb/Interpreter/OptionValueSInt64.h | 114 + include/lldb/Interpreter/OptionValueString.h | 148 + include/lldb/Interpreter/OptionValueUInt64.h | 93 + include/lldb/Interpreter/OptionValueUUID.h | 74 + include/lldb/Interpreter/OptionValues.h | 34 + include/lldb/Interpreter/Options.h | 432 + include/lldb/Interpreter/Property.h | 78 + include/lldb/Interpreter/ScriptInterpreter.h | 454 + include/lldb/Symbol/ArmUnwindInfo.h | 70 + include/lldb/Symbol/Block.h | 441 + include/lldb/Symbol/ClangASTContext.h | 1040 ++ include/lldb/Symbol/ClangASTImporter.h | 350 + .../Symbol/ClangExternalASTSourceCallbacks.h | 147 + .../Symbol/ClangExternalASTSourceCommon.h | 148 + include/lldb/Symbol/ClangUtil.h | 31 + include/lldb/Symbol/CompactUnwindInfo.h | 176 + include/lldb/Symbol/CompileUnit.h | 466 + include/lldb/Symbol/CompilerDecl.h | 94 + include/lldb/Symbol/CompilerDeclContext.h | 113 + include/lldb/Symbol/CompilerType.h | 434 + include/lldb/Symbol/DWARFCallFrameInfo.h | 168 + include/lldb/Symbol/DebugMacros.h | 102 + include/lldb/Symbol/DeclVendor.h | 65 + include/lldb/Symbol/Declaration.h | 240 + include/lldb/Symbol/FuncUnwinders.h | 167 + include/lldb/Symbol/Function.h | 636 + include/lldb/Symbol/GoASTContext.h | 428 + include/lldb/Symbol/JavaASTContext.h | 354 + include/lldb/Symbol/LineEntry.h | 202 + include/lldb/Symbol/LineTable.h | 380 + include/lldb/Symbol/OCamlASTContext.h | 324 + include/lldb/Symbol/ObjectContainer.h | 203 + include/lldb/Symbol/ObjectFile.h | 876 + include/lldb/Symbol/Symbol.h | 283 + include/lldb/Symbol/SymbolContext.h | 591 + include/lldb/Symbol/SymbolContextScope.h | 115 + include/lldb/Symbol/SymbolFile.h | 214 + include/lldb/Symbol/SymbolVendor.h | 178 + include/lldb/Symbol/Symtab.h | 205 + include/lldb/Symbol/TaggedASTType.h | 44 + include/lldb/Symbol/Type.h | 674 + include/lldb/Symbol/TypeList.h | 75 + include/lldb/Symbol/TypeMap.h | 77 + include/lldb/Symbol/TypeSystem.h | 539 + include/lldb/Symbol/UnwindPlan.h | 494 + include/lldb/Symbol/UnwindTable.h | 85 + include/lldb/Symbol/Variable.h | 141 + include/lldb/Symbol/VariableList.h | 86 + include/lldb/Symbol/VerifyDecl.h | 19 + include/lldb/Target/ABI.h | 163 + include/lldb/Target/CPPLanguageRuntime.h | 52 + include/lldb/Target/DynamicLoader.h | 379 + include/lldb/Target/ExecutionContext.h | 708 + include/lldb/Target/ExecutionContextScope.h | 68 + include/lldb/Target/FileAction.h | 59 + include/lldb/Target/InstrumentationRuntime.h | 100 + .../Target/InstrumentationRuntimeStopInfo.h | 47 + include/lldb/Target/JITLoader.h | 83 + include/lldb/Target/JITLoaderList.h | 51 + include/lldb/Target/Language.h | 274 + include/lldb/Target/LanguageRuntime.h | 177 + include/lldb/Target/Memory.h | 162 + include/lldb/Target/MemoryHistory.h | 38 + include/lldb/Target/MemoryRegionInfo.h | 124 + include/lldb/Target/ModuleCache.h | 76 + include/lldb/Target/ObjCLanguageRuntime.h | 426 + include/lldb/Target/OperatingSystem.h | 93 + include/lldb/Target/PathMappingList.h | 139 + include/lldb/Target/Platform.h | 1169 ++ include/lldb/Target/Process.h | 3251 ++++ include/lldb/Target/ProcessInfo.h | 103 + include/lldb/Target/ProcessLaunchInfo.h | 165 + include/lldb/Target/ProcessStructReader.h | 102 + include/lldb/Target/Queue.h | 179 + include/lldb/Target/QueueItem.h | 187 + include/lldb/Target/QueueList.h | 130 + include/lldb/Target/RegisterCheckpoint.h | 55 + include/lldb/Target/RegisterContext.h | 232 + include/lldb/Target/RegisterNumber.h | 62 + include/lldb/Target/SectionLoadHistory.h | 89 + include/lldb/Target/SectionLoadList.h | 80 + include/lldb/Target/StackFrame.h | 564 + include/lldb/Target/StackFrameList.h | 118 + include/lldb/Target/StackID.h | 108 + include/lldb/Target/StopInfo.h | 207 + include/lldb/Target/StructuredDataPlugin.h | 188 + include/lldb/Target/SystemRuntime.h | 362 + include/lldb/Target/Target.h | 1276 ++ include/lldb/Target/TargetList.h | 234 + include/lldb/Target/Thread.h | 1364 ++ include/lldb/Target/ThreadCollection.h | 60 + include/lldb/Target/ThreadList.h | 163 + include/lldb/Target/ThreadPlan.h | 676 + include/lldb/Target/ThreadPlanBase.h | 62 + include/lldb/Target/ThreadPlanCallFunction.h | 164 + .../Target/ThreadPlanCallFunctionUsingABI.h | 59 + .../Target/ThreadPlanCallOnFunctionExit.h | 56 + .../Target/ThreadPlanCallUserExpression.h | 69 + include/lldb/Target/ThreadPlanPython.h | 72 + include/lldb/Target/ThreadPlanRunToAddress.h | 72 + .../lldb/Target/ThreadPlanShouldStopHere.h | 147 + include/lldb/Target/ThreadPlanStepInRange.h | 112 + .../lldb/Target/ThreadPlanStepInstruction.h | 61 + include/lldb/Target/ThreadPlanStepOut.h | 96 + .../Target/ThreadPlanStepOverBreakpoint.h | 59 + include/lldb/Target/ThreadPlanStepOverRange.h | 58 + include/lldb/Target/ThreadPlanStepRange.h | 94 + include/lldb/Target/ThreadPlanStepThrough.h | 67 + include/lldb/Target/ThreadPlanStepUntil.h | 72 + include/lldb/Target/ThreadPlanTracer.h | 104 + include/lldb/Target/ThreadSpec.h | 134 + include/lldb/Target/UnixSignals.h | 142 + include/lldb/Target/Unwind.h | 92 + include/lldb/Target/UnwindAssembly.h | 54 + include/lldb/Utility/AnsiTerminal.h | 136 + include/lldb/Utility/Baton.h | 78 + include/lldb/Utility/CleanUp.h | 261 + include/lldb/Utility/Connection.h | 212 + include/lldb/Utility/ConstString.h | 490 + include/lldb/Utility/DataBuffer.h | 99 + include/lldb/Utility/DataBufferHeap.h | 135 + include/lldb/Utility/DataBufferLLVM.h | 52 + include/lldb/Utility/DataEncoder.h | 402 + include/lldb/Utility/DataExtractor.h | 1158 ++ include/lldb/Utility/Either.h | 126 + include/lldb/Utility/Endian.h | 34 + include/lldb/Utility/FastDemangle.h | 26 + include/lldb/Utility/FileSpec.h | 621 + include/lldb/Utility/Flags.h | 193 + include/lldb/Utility/History.h | 136 + include/lldb/Utility/IOObject.h | 56 + include/lldb/Utility/Iterable.h | 202 + include/lldb/Utility/JSON.h | 287 + include/lldb/Utility/LLDBAssert.h | 25 + include/lldb/Utility/Log.h | 216 + include/lldb/Utility/Logging.h | 69 + include/lldb/Utility/NameMatches.h | 29 + include/lldb/Utility/Range.h | 60 + include/lldb/Utility/RegularExpression.h | 219 + include/lldb/Utility/SafeMachO.h | 119 + include/lldb/Utility/SelectHelper.h | 73 + include/lldb/Utility/SharedCluster.h | 94 + include/lldb/Utility/SharingPtr.h | 625 + include/lldb/Utility/Status.h | 279 + include/lldb/Utility/Stream.h | 548 + include/lldb/Utility/StreamCallback.h | 36 + include/lldb/Utility/StreamGDBRemote.h | 48 + include/lldb/Utility/StreamString.h | 56 + include/lldb/Utility/StreamTee.h | 141 + include/lldb/Utility/StringExtractor.h | 137 + include/lldb/Utility/StringLexer.h | 60 + include/lldb/Utility/StringList.h | 139 + include/lldb/Utility/StructuredData.h | 556 + include/lldb/Utility/TaskPool.h | 92 + .../lldb/Utility/TildeExpressionResolver.h | 65 + include/lldb/Utility/Timeout.h | 71 + include/lldb/Utility/Timer.h | 79 + include/lldb/Utility/TraceOptions.h | 61 + include/lldb/Utility/UUID.h | 101 + include/lldb/Utility/UriParser.h | 32 + include/lldb/Utility/UserID.h | 122 + include/lldb/Utility/VASPrintf.h | 21 + include/lldb/Utility/VMRange.h | 128 + include/lldb/lldb-defines.h | 165 + include/lldb/lldb-enumerations.h | 1095 ++ include/lldb/lldb-forward.h | 493 + include/lldb/lldb-private-defines.h | 38 + include/lldb/lldb-private-enumerations.h | 259 + include/lldb/lldb-private-forward.h | 40 + include/lldb/lldb-private-interfaces.h | 115 + include/lldb/lldb-private-types.h | 132 + include/lldb/lldb-private.h | 29 + include/lldb/lldb-public.h | 18 + include/lldb/lldb-types.h | 96 + include/lldb/lldb-versioning.h | 1545 ++ lit/CMakeLists.txt | 68 + lit/Expr/Inputs/anonymous-struct.cpp | 26 + lit/Expr/Inputs/call-function.cpp | 53 + lit/Expr/TestCallStdStringFunction.test | 14 + lit/Expr/TestCallStopAndContinue.test | 12 + lit/Expr/TestCallUserAnonTypedef.test | 11 + lit/Expr/TestCallUserDefinedFunction.test | 20 + lit/Expr/lit.local.cfg | 1 + lit/Unit/lit.cfg | 36 + lit/Unit/lit.site.cfg.in | 26 + lit/lit.cfg | 223 + lit/lit.site.cfg.in | 40 + lldb.xcodeproj/project.pbxproj | 10562 +++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/LLDB.xcscheme | 107 + .../xcschemes/Run Testsuite.xcscheme | 123 + .../xcschemes/darwin-debug.xcscheme | 108 + .../xcshareddata/xcschemes/desktop.xcscheme | 80 + .../xcschemes/launcherRootXPCService.xcscheme | 72 + .../xcschemes/launcherXPCService.xcscheme | 76 + .../xcschemes/lldb-gtest.xcscheme | 92 + .../xcschemes/lldb-python-test-suite.xcscheme | 80 + .../xcshareddata/xcschemes/lldb-tool.xcscheme | 215 + lldb.xcworkspace/contents.xcworkspacedata | 13 + packages/Python/lldbsuite/.clang-format | 4 + packages/Python/lldbsuite/__init__.py | 29 + .../Python/lldbsuite/pre_kill_hook/README.md | 55 + .../lldbsuite/pre_kill_hook/__init__.py | 1 + .../Python/lldbsuite/pre_kill_hook/darwin.py | 46 + .../Python/lldbsuite/pre_kill_hook/linux.py | 76 + .../lldbsuite/pre_kill_hook/tests/__init__.py | 0 .../pre_kill_hook/tests/test_darwin.py | 107 + .../pre_kill_hook/tests/test_linux.py | 133 + packages/Python/lldbsuite/support/__init__.py | 0 .../Python/lldbsuite/support/encoded_file.py | 65 + packages/Python/lldbsuite/support/fs.py | 65 + .../Python/lldbsuite/support/funcutils.py | 24 + packages/Python/lldbsuite/support/gmodules.py | 29 + .../Python/lldbsuite/support/optional_with.py | 58 + packages/Python/lldbsuite/support/seven.py | 25 + packages/Python/lldbsuite/support/sockutil.py | 24 + packages/Python/lldbsuite/test/.categories | 0 packages/Python/lldbsuite/test/Makefile | 33 + .../Python/lldbsuite/test/README-TestSuite | 173 + packages/Python/lldbsuite/test/__init__.py | 7 + .../lldbsuite/test/android/platform/Makefile | 4 + .../platform/TestDefaultCacheLineSize.py | 47 + .../lldbsuite/test/android/platform/main.cpp | 13 + .../api/check_public_api_headers/Makefile | 5 + .../TestPublicAPIHeaders.py | 68 + .../main.cpp.template | 24 + .../lldbsuite/test/api/listeners/Makefile | 6 + .../test/api/listeners/TestListener.py | 71 + .../lldbsuite/test/api/listeners/main.c | 7 + .../test/api/multiple-debuggers/.categories | 1 + .../test/api/multiple-debuggers/Makefile | 8 + .../TestMultipleDebuggers.py | 54 + .../multi-process-driver.cpp | 287 + .../test/api/multiple-debuggers/testprog.cpp | 12 + .../test/api/multiple-targets/Makefile | 8 + .../multiple-targets/TestMultipleTargets.py | 44 + .../test/api/multiple-targets/main.cpp | 31 + .../lldbsuite/test/api/multithreaded/Makefile | 9 + .../api/multithreaded/TestMultithreaded.py | 108 + .../lldbsuite/test/api/multithreaded/common.h | 68 + .../api/multithreaded/driver.cpp.template | 48 + .../test/api/multithreaded/inferior.cpp | 17 + .../multithreaded/listener_test.cpp.template | 74 + .../test_breakpoint_callback.cpp.template | 49 + ...st_listener_event_description.cpp.template | 97 + ..._listener_event_process_state.cpp.template | 63 + .../test_listener_resume.cpp.template | 53 + .../test/arm_emulation/TestEmulations.py | 57 + .../new-test-files/test-add-1-arm.dat | 111 + .../new-test-files/test-add-1-thumb.dat | 111 + .../new-test-files/test-add-10-thumb.dat | 111 + .../new-test-files/test-add-11-thumb.dat | 111 + .../new-test-files/test-add-12-thumb.dat | 111 + .../new-test-files/test-add-2-arm.dat | 111 + .../new-test-files/test-add-2-thumb.dat | 111 + .../new-test-files/test-add-3-arm.dat | 111 + .../new-test-files/test-add-3-thumb.dat | 111 + .../new-test-files/test-add-4-arm.dat | 111 + .../new-test-files/test-add-4-thumb.dat | 111 + .../new-test-files/test-add-5-arm.dat | 111 + .../new-test-files/test-add-5-thumb.dat | 111 + .../new-test-files/test-add-6-arm.dat | 111 + .../new-test-files/test-add-6-thumb.dat | 111 + .../new-test-files/test-add-7-arm.dat | 111 + .../new-test-files/test-add-7-thumb.dat | 111 + .../new-test-files/test-add-8-arm.dat | 111 + .../new-test-files/test-add-8-thumb.dat | 111 + .../new-test-files/test-add-9-thumb.dat | 111 + .../new-test-files/test-bic-1-arm.dat | 111 + .../new-test-files/test-bic-1-thumb.dat | 111 + .../new-test-files/test-ldmia-1-arm.dat | 119 + .../new-test-files/test-ldmia-1-thumb.dat | 119 + .../new-test-files/test-ldmia-2-arm.dat | 123 + .../new-test-files/test-ldmia-2-thumb.dat | 123 + .../new-test-files/test-ldmia-3-arm.dat | 119 + .../new-test-files/test-ldmia-3-thumb.dat | 119 + .../new-test-files/test-ldr-1-arm.dat | 118 + .../new-test-files/test-ldr-1-thumb.dat | 118 + .../new-test-files/test-ldr-10-thumb.dat | 118 + .../new-test-files/test-ldr-11-thumb.dat | 118 + .../new-test-files/test-ldr-12-thumb.dat | 118 + .../new-test-files/test-ldr-2-arm.dat | 118 + .../new-test-files/test-ldr-2-thumb.dat | 118 + .../new-test-files/test-ldr-3-arm.dat | 118 + .../new-test-files/test-ldr-3-thumb.dat | 118 + .../new-test-files/test-ldr-4-arm.dat | 118 + .../new-test-files/test-ldr-4-thumb.dat | 118 + .../new-test-files/test-ldr-5-arm.dat | 118 + .../new-test-files/test-ldr-5-thumb.dat | 118 + .../new-test-files/test-ldr-6-arm.dat | 118 + .../new-test-files/test-ldr-6-thumb.dat | 118 + .../new-test-files/test-ldr-7-arm.dat | 118 + .../new-test-files/test-ldr-7-thumb.dat | 118 + .../new-test-files/test-ldr-8-arm.dat | 118 + .../new-test-files/test-ldr-8-thumb.dat | 118 + .../new-test-files/test-ldr-9-thumb.dat | 118 + .../new-test-files/test-ldrd-1-arm.dat | 119 + .../new-test-files/test-ldrd-1-thumb.dat | 119 + .../new-test-files/test-ldrd-2-thumb.dat | 119 + .../new-test-files/test-ldrh-1-thumb.dat | 118 + .../new-test-files/test-ldrsh-1-arm.dat | 118 + .../new-test-files/test-ldrsh-2-arm.dat | 118 + .../new-test-files/test-mov-1-arm.dat | 111 + .../new-test-files/test-mov-1-thumb.dat | 111 + .../new-test-files/test-mov-10-thumb.dat | 111 + .../new-test-files/test-mov-11-thumb.dat | 111 + .../new-test-files/test-mov-12-thumb.dat | 111 + .../new-test-files/test-mov-13-thumb.dat | 111 + .../new-test-files/test-mov-14-thumb.dat | 111 + .../new-test-files/test-mov-15-thumb.dat | 111 + .../new-test-files/test-mov-16-thumb.dat | 111 + .../new-test-files/test-mov-17-thumb.dat | 111 + .../new-test-files/test-mov-18-thumb.dat | 111 + .../new-test-files/test-mov-19-thumb.dat | 111 + .../new-test-files/test-mov-2-arm.dat | 111 + .../new-test-files/test-mov-2-thumb.dat | 111 + .../new-test-files/test-mov-20-thumb.dat | 111 + .../new-test-files/test-mov-21-thumb.dat | 111 + .../new-test-files/test-mov-22-thumb.dat | 111 + .../new-test-files/test-mov-23-thumb.dat | 111 + .../new-test-files/test-mov-24-thumb.dat | 111 + .../new-test-files/test-mov-25-thumb.dat | 111 + .../new-test-files/test-mov-26-thumb.dat | 111 + .../new-test-files/test-mov-27-thumb.dat | 111 + .../new-test-files/test-mov-28-thumb.dat | 111 + .../new-test-files/test-mov-29-thumb.dat | 111 + .../new-test-files/test-mov-3-arm.dat | 111 + .../new-test-files/test-mov-3-thumb.dat | 111 + .../new-test-files/test-mov-30-thumb.dat | 111 + .../new-test-files/test-mov-31-thumb.dat | 111 + .../new-test-files/test-mov-4-arm.dat | 111 + .../new-test-files/test-mov-4-thumb.dat | 111 + .../new-test-files/test-mov-5-arm.dat | 111 + .../new-test-files/test-mov-5-thumb.dat | 111 + .../new-test-files/test-mov-6-arm.dat | 111 + .../new-test-files/test-mov-6-thumb.dat | 111 + .../new-test-files/test-mov-7-thumb.dat | 111 + .../new-test-files/test-mov-8-thumb.dat | 111 + .../new-test-files/test-mov-9-thumb.dat | 111 + .../new-test-files/test-moveq-1-arm.dat | 111 + .../new-test-files/test-movs-1-arm.dat | 111 + .../new-test-files/test-mvn-1-arm.dat | 111 + .../new-test-files/test-mvn-1-thumb.dat | 111 + .../new-test-files/test-mvn-2-arm.dat | 111 + .../new-test-files/test-mvn-2-thumb.dat | 111 + .../new-test-files/test-mvn-3-arm.dat | 111 + .../new-test-files/test-mvn-3-thumb.dat | 111 + .../new-test-files/test-mvn-4-arm.dat | 111 + .../new-test-files/test-mvn-4-thumb.dat | 111 + .../new-test-files/test-pop-1-arm.dat | 121 + .../new-test-files/test-pop-1-thumb.dat | 121 + .../new-test-files/test-pop-2-arm.dat | 118 + .../new-test-files/test-pop-2-thumb.dat | 118 + .../new-test-files/test-pop-3-thumb.dat | 118 + .../new-test-files/test-push-1-arm.dat | 111 + .../new-test-files/test-push-1-thumb.dat | 111 + .../new-test-files/test-push-2-arm.dat | 111 + .../new-test-files/test-push-2-thumb.dat | 111 + .../new-test-files/test-push-3-arm.dat | 111 + .../new-test-files/test-push-3-thumb.dat | 111 + .../new-test-files/test-str-1-arm.dat | 111 + .../new-test-files/test-str-1-thumb.dat | 111 + .../new-test-files/test-str-2-arm.dat | 111 + .../new-test-files/test-str-2-thumb.dat | 111 + .../new-test-files/test-str-3-arm.dat | 111 + .../new-test-files/test-str-3-thumb.dat | 111 + .../new-test-files/test-str-4-arm.dat | 111 + .../new-test-files/test-str-4-thumb.dat | 111 + .../new-test-files/test-str-5-arm.dat | 111 + .../new-test-files/test-strb-1-arm.dat | 111 + .../new-test-files/test-strb-2-arm.dat | 111 + .../new-test-files/test-strbt-1-arm.dat | 111 + .../new-test-files/test-strd-1-thumb.dat | 111 + .../new-test-files/test-strt-1-arm.dat | 111 + .../new-test-files/test-sub-1-arm.dat | 111 + .../new-test-files/test-sub-1-thumb.dat | 111 + .../new-test-files/test-sub-10-arm.dat | 111 + .../new-test-files/test-sub-2-arm.dat | 111 + .../new-test-files/test-sub-2-thumb.dat | 111 + .../new-test-files/test-sub-3-arm.dat | 111 + .../new-test-files/test-sub-3-thumb.dat | 111 + .../new-test-files/test-sub-4-arm.dat | 111 + .../new-test-files/test-sub-4-thumb.dat | 111 + .../new-test-files/test-sub-5-arm.dat | 111 + .../new-test-files/test-sub-5-thumb.dat | 111 + .../new-test-files/test-sub-6-arm.dat | 111 + .../new-test-files/test-sub-6-thumb.dat | 111 + .../new-test-files/test-sub-8-arm.dat | 111 + .../new-test-files/test-sub-9-arm.dat | 111 + .../new-test-files/test-subs-1-arm.dat | 111 + .../new-test-files/test-subs-1-thumb.dat | 111 + .../new-test-files/test-subs-10-thumb.dat | 111 + .../new-test-files/test-subs-2-thumb.dat | 111 + .../new-test-files/test-subs-3-thumb.dat | 111 + .../new-test-files/test-subs-4-thumb.dat | 111 + .../new-test-files/test-subs-5-thumb.dat | 111 + .../new-test-files/test-subs-6-thumb.dat | 111 + .../new-test-files/test-subs-8-thumb.dat | 111 + .../new-test-files/test-subs-9-thumb.dat | 111 + .../new-test-files/test-vpop-1-thumb.dat | 125 + .../new-test-files/test-vpop-2-thumb.dat | 118 + .../new-test-files/test-vpop-3-thumb.dat | 121 + .../new-test-files/test-vpush-1-thumb.dat | 111 + .../new-test-files/test-vpush-2-thumb.dat | 111 + .../new-test-files/test-vpush-3-thumb.dat | 111 + .../Python/lldbsuite/test/attic/dotest.pl | 44 + .../Python/lldbsuite/test/attic/tester.py | 149 + packages/Python/lldbsuite/test/bench-history | 206 + packages/Python/lldbsuite/test/bench.py | 77 + .../test/benchmarks/continue/Makefile | 5 + .../continue/TestBenchmarkContinue.py | 73 + .../test/benchmarks/continue/main.cpp | 36 + .../benchmarks/disassembly/TestDisassembly.py | 165 + .../TestDoAttachThenDisassembly.py | 70 + .../TestXcode41Vs42GDBDisassembly.py | 120 + .../test/benchmarks/expression/Makefile | 5 + .../expression/TestExpressionCmd.py | 83 + .../expression/TestRepeatedExprs.py | 141 + .../test/benchmarks/expression/main.cpp | 51 + .../TestFrameVariableResponse.py | 76 + .../test/benchmarks/libcxxlist/Makefile | 5 + .../libcxxlist/TestBenchmarkLibcxxList.py | 66 + .../test/benchmarks/libcxxlist/main.cpp | 11 + .../test/benchmarks/libcxxmap/Makefile | 5 + .../libcxxmap/TestBenchmarkLibcxxMap.py | 66 + .../test/benchmarks/libcxxmap/main.cpp | 11 + .../benchmarks/startup/TestStartupDelays.py | 92 + .../benchmarks/stepping/TestSteppingSpeed.py | 76 + .../TestCompileRunToBreakpointTurnaround.py | 131 + .../Python/lldbsuite/test/concurrent_base.py | 288 + .../Python/lldbsuite/test/configuration.py | 181 + packages/Python/lldbsuite/test/crashinfo.c | 64 + packages/Python/lldbsuite/test/darwin_log.py | 457 + packages/Python/lldbsuite/test/decorators.py | 747 + packages/Python/lldbsuite/test/dosep.py | 1810 ++ packages/Python/lldbsuite/test/dotest.py | 1333 ++ packages/Python/lldbsuite/test/dotest_args.py | 303 + .../lldbsuite/test/driver/batch_mode/Makefile | 5 + .../test/driver/batch_mode/TestBatchMode.py | 188 + .../lldbsuite/test/driver/batch_mode/main.c | 41 + .../test/example/TestSequenceFunctions.py | 37 + .../test/expression_command/.categories | 1 + .../anonymous-struct/Makefile | 12 + .../TestCallUserAnonTypedef.py | 45 + .../anonymous-struct/main.cpp | 26 + .../calculator_mode/TestCalculatorMode.py | 27 + .../expression_command/call-function/Makefile | 15 + .../TestCallStdStringFunction.py | 51 + .../call-function/TestCallStopAndContinue.py | 58 + .../TestCallUserDefinedFunction.py | 62 + .../expression_command/call-function/main.cpp | 53 + .../expression_command/call-restarts/Makefile | 5 + .../call-restarts/TestCallThatRestarts.py | 166 + .../call-restarts/lotta-signals.c | 61 + .../expression_command/call-throws/Makefile | 6 + .../call-throws/TestCallThatThrows.py | 104 + .../call-throws/call-throws.m | 47 + .../test/expression_command/char/Makefile | 5 + .../expression_command/char/TestExprsChar.py | 66 + .../test/expression_command/char/main.cpp | 10 + .../expr-in-syscall/Makefile | 5 + .../TestExpressionInSyscall.py | 92 + .../expr-in-syscall/main.cpp | 12 + .../test/expression_command/fixits/Makefile | 12 + .../expression_command/fixits/TestFixIts.py | 72 + .../test/expression_command/fixits/main.cpp | 25 + .../expression_command/formatters/Makefile | 5 + .../formatters/TestFormatters.py | 298 + .../expression_command/formatters/foosynth.py | 33 + .../formatters/formatters.py | 17 + .../expression_command/formatters/main.cpp | 48 + .../ir-interpreter-phi-nodes/Makefile | 5 + .../TestIRInterpreterPHINodes.py | 43 + .../ir-interpreter-phi-nodes/main.cpp | 17 + .../ir-interpreter/Makefile | 7 + .../ir-interpreter/TestIRInterpreter.py | 87 + .../expression_command/ir-interpreter/main.c | 7 + .../expression_command/issue_11588/Makefile | 5 + .../issue_11588/Test11588.py | 69 + .../expression_command/issue_11588/main.cpp | 54 + .../expression_command/issue_11588/s11588.py | 28 + .../test/expression_command/macros/Makefile | 8 + .../expression_command/macros/TestMacros.py | 131 + .../test/expression_command/macros/macro1.h | 17 + .../test/expression_command/macros/macro2.h | 8 + .../test/expression_command/macros/main.cpp | 15 + .../expression_command/multiline/Makefile | 5 + .../multiline/TestMultilineExpressions.py | 90 + .../test/expression_command/multiline/main.c | 6 + .../test/expression_command/options/Makefile | 5 + .../options/TestExprOptions.py | 65 + .../test/expression_command/options/foo.cpp | 11 + .../test/expression_command/options/main.cpp | 15 + .../persist_objc_pointeetype/Makefile | 7 + .../TestPersistObjCPointeeType.py | 53 + .../persist_objc_pointeetype/main.m | 80 + .../persistent_ptr_update/Makefile | 7 + .../TestPersistentPtrUpdate.py | 41 + .../persistent_ptr_update/main.c | 11 + .../persistent_types/Makefile | 5 + .../TestNestedPersistentTypes.py | 45 + .../persistent_types/TestPersistentTypes.py | 86 + .../persistent_types/main.c | 14 + .../persistent_variables/Makefile | 5 + .../TestPersistentVariables.py | 55 + .../persistent_variables/main.c | 14 + .../expression_command/po_verbosity/Makefile | 6 + .../po_verbosity/TestPoVerbosity.py | 63 + .../expression_command/po_verbosity/main.m | 9 + .../expression_command/radar_8638051/Makefile | 5 + .../radar_8638051/Test8638051.py | 40 + .../expression_command/radar_8638051/main.c | 54 + .../expression_command/radar_9531204/Makefile | 5 + .../radar_9531204/TestPrintfAfterUp.py | 45 + .../expression_command/radar_9531204/main.c | 25 + .../expression_command/radar_9673664/Makefile | 5 + .../radar_9673664/TestExprHelpExamples.py | 48 + .../expression_command/radar_9673664/main.c | 16 + .../save_jit_objects/Makefile | 5 + .../save_jit_objects/TestSaveJITObjects.py | 51 + .../save_jit_objects/main.c | 14 + .../test/expression_command/test/Makefile | 5 + .../test/expression_command/test/TestExprs.py | 255 + .../expression_command/test/TestExprs2.py | 65 + .../test/expression_command/test/main.cpp | 44 + .../test/expression_command/timeout/Makefile | 5 + .../timeout/TestCallWithTimeout.py | 80 + .../timeout/wait-a-while.cpp | 35 + .../expression_command/top-level/Makefile | 12 + .../top-level/TestTopLevelExprs.py | 112 + .../expression_command/top-level/dummy.cpp | 7 + .../expression_command/top-level/main.cpp | 9 + .../expression_command/top-level/test.cpp | 107 + .../expression_command/two-files/Makefile | 7 + .../TestObjCTypeQueryFromOtherCompileUnit.py | 41 + .../test/expression_command/two-files/foo.m | 28 + .../test/expression_command/two-files/main.m | 22 + .../unwind_expression/Makefile | 5 + .../unwind_expression/TestUnwindExpression.py | 103 + .../unwind_expression/main.cpp | 22 + .../functionalities/abbreviation/.categories | 1 + .../abbreviation/TestAbbreviations.py | 112 + .../abbreviation/TestCommonShortSpellings.py | 41 + .../test/functionalities/alias/.categories | 1 + .../apropos_with_process/Makefile | 5 + .../TestAproposWithProcess.py | 46 + .../apropos_with_process/main.cpp | 15 + .../test/functionalities/archives/Makefile | 9 + .../test/functionalities/archives/README | 62 + .../archives/TestBSDArchives.py | 70 + .../test/functionalities/archives/a.c | 19 + .../test/functionalities/archives/b.c | 19 + .../test/functionalities/archives/main.c | 17 + .../test/functionalities/asan/Makefile | 6 + .../functionalities/asan/TestMemoryHistory.py | 134 + .../functionalities/asan/TestReportData.py | 94 + .../test/functionalities/asan/main.c | 34 + .../functionalities/attach_resume/Makefile | 7 + .../attach_resume/TestAttachResume.py | 94 + .../functionalities/attach_resume/main.cpp | 35 + .../functionalities/avoids-fd-leak/Makefile | 5 + .../avoids-fd-leak/TestFdLeak.py | 105 + .../functionalities/avoids-fd-leak/main.c | 28 + .../functionalities/backticks/.categories | 1 + .../backticks/TestBackticksWithoutATarget.py | 24 + .../breakpoint/address_breakpoints/Makefile | 6 + .../TestAddressBreakpoints.py | 99 + .../TestBadAddressBreakpoints.py | 49 + .../breakpoint/address_breakpoints/main.c | 8 + .../breakpoint_case_sensitivity/Makefile | 6 + .../TestBreakpointCaseSensitivity.py | 129 + .../breakpoint_case_sensitivity/main.c | 8 + .../breakpoint/breakpoint_command/Makefile | 5 + .../TestBreakpointCommand.py | 270 + .../TestBreakpointCommandsFromPython.py | 110 + .../TestRegexpBreakCommand.py | 72 + .../breakpoint/breakpoint_command/a.c | 9 + .../breakpoint/breakpoint_command/b.c | 9 + .../breakpoint/breakpoint_command/bktptcmd.py | 7 + .../breakpoint/breakpoint_command/main.c | 13 + .../breakpoint/breakpoint_conditions/Makefile | 6 + .../TestBreakpointConditions.py | 237 + .../breakpoint/breakpoint_conditions/main.c | 54 + .../breakpoint/breakpoint_ids/Makefile | 9 + .../breakpoint_ids/TestBreakpointIDs.py | 60 + .../breakpoint/breakpoint_ids/main.cpp | 65 + .../breakpoint_ignore_count/Makefile | 5 + .../TestBreakpointIgnoreCount.py | 152 + .../breakpoint/breakpoint_ignore_count/main.c | 54 + .../breakpoint_in_delayslot/Makefile | 6 + .../TestAvoidBreakpointInDelaySlot.py | 89 + .../breakpoint/breakpoint_in_delayslot/main.c | 21 + .../breakpoint/breakpoint_language/Makefile | 6 + .../TestBreakpointLanguage.py | 137 + .../breakpoint/breakpoint_language/a.c | 5 + .../breakpoint/breakpoint_language/b.cpp | 5 + .../breakpoint/breakpoint_language/main.cpp | 11 + .../breakpoint/breakpoint_locations/Makefile | 9 + .../TestBreakpointLocations.py | 106 + .../breakpoint/breakpoint_locations/main.c | 43 + .../breakpoint/breakpoint_names/Makefile | 5 + .../breakpoint_names/TestBreakpointNames.py | 141 + .../breakpoint/breakpoint_names/main.c | 54 + .../breakpoint/breakpoint_options/Makefile | 5 + .../TestBreakpointOptions.py | 115 + .../breakpoint/breakpoint_options/foo.cpp | 12 + .../breakpoint/breakpoint_options/main.cpp | 4 + .../breakpoint_set_restart/Makefile | 5 + .../TestBreakpointSetRestart.py | 52 + .../breakpoint_set_restart/main.cpp | 25 + .../breakpoint/comp_dir_symlink/Makefile | 7 + .../comp_dir_symlink/TestCompDirSymLink.py | 73 + .../breakpoint/comp_dir_symlink/main.cpp | 13 + .../consecutive_breakpoints/Makefile | 9 + .../TestConsecutiveBreakpoints.py | 104 + .../consecutive_breakpoints/main.cpp | 19 + .../functionalities/breakpoint/cpp/Makefile | 9 + .../cpp/TestCPPBreakpointLocations.py | 114 + .../functionalities/breakpoint/cpp/main.cpp | 83 + .../breakpoint/cpp_exception/Makefile | 5 + .../TestCPPExceptionBreakpoint.py | 54 + .../breakpoint/cpp_exception/main.cpp | 13 + .../breakpoint/debugbreak/Makefile | 5 + .../breakpoint/debugbreak/TestDebugBreak.py | 59 + .../breakpoint/debugbreak/main.c | 29 + .../dummy_target_breakpoints/Makefile | 9 + .../TestBreakpointsWithNoTargets.py | 74 + .../dummy_target_breakpoints/main.c | 11 + .../Makefile | 6 + .../TestHWBreakMultiThread.py | 114 + .../main.cpp | 51 + .../breakpoint/inlined_breakpoints/Makefile | 5 + .../TestInlinedBreakpoints.py | 69 + .../inlined_breakpoints/basic_type.cpp | 178 + .../breakpoint/inlined_breakpoints/int.cpp | 9 + .../breakpoint/move_nearest/Makefile | 8 + .../move_nearest/TestMoveNearest.py | 63 + .../breakpoint/move_nearest/foo.cpp | 3 + .../breakpoint/move_nearest/foo.h | 6 + .../breakpoint/move_nearest/main.cpp | 9 + .../functionalities/breakpoint/objc/Makefile | 7 + .../breakpoint/objc/TestObjCBreakpoints.py | 132 + .../functionalities/breakpoint/objc/main.m | 98 + .../breakpoint/serialize/Makefile | 5 + .../serialize/TestBreakpointSerialization.py | 288 + .../breakpoint/serialize/main.c | 54 + .../breakpoint/source_regexp/Makefile | 5 + .../TestSourceRegexBreakpoints.py | 106 + .../breakpoint/source_regexp/a.c | 16 + .../breakpoint/source_regexp/a.h | 1 + .../breakpoint/source_regexp/main.c | 17 + .../breakpoint/step_over_breakpoint/Makefile | 9 + .../TestStepOverBreakpoint.py | 119 + .../breakpoint/step_over_breakpoint/main.cpp | 12 + .../command_history/.categories | 1 + .../command_history/TestCommandHistory.py | 108 + .../functionalities/command_regex/.categories | 1 + .../command_regex/TestCommandRegex.py | 63 + .../command_script/.categories | 1 + .../functionalities/command_script/Makefile | 5 + .../command_script/TestCommandScript.py | 146 + .../command_script/bug11569.py | 6 + .../command_script/import/Makefile | 6 + .../command_script/import/TestImport.py | 79 + .../command_script/import/bar/bar.py | 15 + .../command_script/import/bar/barutil.py | 2 + .../command_script/import/dummymodule.py | 2 + .../command_script/import/foo/bar/foobar.py | 6 + .../command_script/import/foo/foo.py | 6 + .../command_script/import/foo/foo2.py | 11 + .../command_script/import/main.c | 15 + .../import/rdar-12586188/Makefile | 3 + .../import/rdar-12586188/TestRdar12586188.py | 39 + .../import/rdar-12586188/fail12586188.py | 4 + .../import/rdar-12586188/fail212586188.py | 4 + .../import/thepackage/TPunitA.py | 7 + .../import/thepackage/TPunitB.py | 7 + .../import/thepackage/__init__.py | 11 + .../functionalities/command_script/main.cpp | 70 + .../functionalities/command_script/mysto.py | 25 + .../functionalities/command_script/py_import | 12 + .../functionalities/command_script/welcome.py | 53 + .../command_script_alias/.categories | 1 + .../TestCommandScriptAlias.py | 40 + .../command_script_alias/tcsacmd.py | 12 + .../TestCommandScriptImmediateOutput.py | 97 + .../custom_command.py | 19 + .../command_source/.categories | 1 + .../test/functionalities/command_source/.lldb | 1 + .../command_source/TestCommandSource.py | 39 + .../test/functionalities/command_source/my.py | 7 + .../functionalities/completion/.categories | 1 + .../test/functionalities/completion/Makefile | 5 + .../completion/TestCompletion.py | 373 + .../test/functionalities/completion/main.cpp | 14 + .../functionalities/conditional_break/.lldb | 3 + .../conditional_break/Makefile | 5 + .../conditional_break/TestConditionalBreak.py | 144 + .../conditional_break/conditional_break.py | 30 + .../functionalities/conditional_break/main.c | 54 + .../functionalities/darwin_log/.categories | 1 + .../functionalities/darwin_log/basic/Makefile | 5 + .../darwin_log/basic/TestDarwinLogBasic.py | 36 + .../functionalities/darwin_log/basic/main.c | 32 + .../darwin_log/common/darwin_log_common.h | 6 + .../exact_match/activity-chain/Makefile | 5 + .../TestDarwinLogFilterMatchActivityChain.py | 123 + .../filter/exact_match/activity-chain/main.c | 43 + .../filter/exact_match/activity/Makefile | 5 + .../TestDarwinLogFilterMatchActivity.py | 127 + .../filter/exact_match/activity/main.c | 43 + .../filter/exact_match/category/Makefile | 5 + .../TestDarwinLogFilterMatchCategory.py | 127 + .../filter/exact_match/category/main.c | 43 + .../filter/exact_match/message/Makefile | 5 + .../TestDarwinLogFilterMatchMessage.py | 147 + .../filter/exact_match/message/main.c | 35 + .../filter/exact_match/subsystem/Makefile | 5 + .../TestDarwinLogFilterMatchSubsystem.py | 127 + .../filter/exact_match/subsystem/main.c | 43 + .../filter/regex/activity-chain/Makefile | 5 + .../TestDarwinLogFilterRegexActivityChain.py | 138 + .../filter/regex/activity-chain/main.c | 43 + .../darwin_log/filter/regex/activity/Makefile | 5 + .../TestDarwinLogFilterRegexActivity.py | 143 + .../darwin_log/filter/regex/activity/main.c | 43 + .../darwin_log/filter/regex/category/Makefile | 5 + .../TestDarwinLogFilterRegexCategory.py | 143 + .../darwin_log/filter/regex/category/main.c | 43 + .../darwin_log/filter/regex/message/Makefile | 5 + .../TestDarwinLogFilterRegexMessage.py | 128 + .../darwin_log/filter/regex/message/main.c | 35 + .../filter/regex/subsystem/Makefile | 5 + .../TestDarwinLogFilterRegexSubsystem.py | 160 + .../darwin_log/filter/regex/subsystem/main.c | 43 + .../darwin_log/format/Makefile | 5 + .../format/TestDarwinLogMessageFormat.py | 188 + .../functionalities/darwin_log/format/main.c | 41 + .../darwin_log/source/debug/Makefile | 5 + .../source/debug/TestDarwinLogSourceDebug.py | 81 + .../darwin_log/source/debug/main.c | 34 + .../darwin_log/source/info/Makefile | 5 + .../source/info/TestDarwinLogSourceInfo.py | 84 + .../darwin_log/source/info/main.c | 34 + .../data-formatter/.categories | 1 + .../data-formatter/boolreference/Makefile | 9 + .../boolreference/TestFormattersBoolRefPtr.py | 81 + .../data-formatter/boolreference/main.mm | 31 + .../data-formatter/compactvectors/Makefile | 7 + .../compactvectors/TestCompactVectors.py | 63 + .../data-formatter/compactvectors/main.cpp | 26 + .../data-formatter-advanced/Makefile | 5 + .../TestDataFormatterAdv.py | 322 + .../data-formatter-advanced/main.cpp | 174 + .../data-formatter-categories/Makefile | 5 + .../TestDataFormatterCategories.py | 359 + .../data-formatter-categories/main.cpp | 46 + .../data-formatter-cpp/Makefile | 5 + .../TestDataFormatterCpp.py | 298 + .../data-formatter-cpp/main.cpp | 121 + .../data-formatter-disabling/Makefile | 5 + .../TestDataFormatterDisabling.py | 91 + .../data-formatter-disabling/main.cpp | 18 + .../data-formatter-enum-format/Makefile | 5 + .../TestDataFormatterEnumFormat.py | 67 + .../data-formatter-enum-format/main.cpp | 13 + .../data-formatter-globals/Makefile | 5 + .../TestDataFormatterGlobals.py | 71 + .../data-formatter-globals/main.cpp | 27 + .../data-formatter-named-summaries/Makefile | 5 + .../TestDataFormatterNamedSummaries.py | 133 + .../data-formatter-named-summaries/main.cpp | 59 + .../data-formatter-objc/.categories | 1 + .../data-formatter-objc/Makefile | 9 + .../TestDataFormatterObjC.py | 511 + .../data-formatter/data-formatter-objc/main.m | 616 + .../data-formatter-objc/nsindexpath/Makefile | 9 + .../TestDataFormatterNSIndexPath.py | 115 + .../data-formatter-objc/nsindexpath/main.m | 31 + .../data-formatter-objc/nsstring/Makefile | 9 + .../nsstring/TestDataFormatterNSString.py | 121 + .../data-formatter-objc/nsstring/main.m | 99 + .../data-formatter-proper-plurals/Makefile | 9 + .../TestFormattersOneIsSingular.py | 81 + .../data-formatter-proper-plurals/main.m | 31 + .../data-formatter-ptr-to-array/Makefile | 5 + .../TestPtrToArrayFormatting.py | 59 + .../data-formatter-ptr-to-array/main.cpp | 17 + .../data-formatter-python-synth/Makefile | 5 + .../TestDataFormatterPythonSynth.py | 291 + .../fooSynthProvider.py | 30 + .../data-formatter-python-synth/ftsp.py | 40 + .../data-formatter-python-synth/main.cpp | 66 + .../data-formatter-script/Makefile | 5 + .../TestDataFormatterScript.py | 185 + .../data-formatter-script/main.cpp | 53 + .../data-formatter-skip-summary/Makefile | 15 + .../TestDataFormatterSkipSummary.py | 205 + .../data-formatter-skip-summary/main.cpp | 57 + .../data-formatter-smart-array/Makefile | 5 + .../TestDataFormatterSmartArray.py | 459 + .../data-formatter-smart-array/main.cpp | 65 + .../data-formatter-stl/libcxx/atomic/Makefile | 5 + .../libcxx/atomic/TestLibCxxAtomic.py | 62 + .../data-formatter-stl/libcxx/atomic/main.cpp | 26 + .../libcxx/function/Makefile | 5 + .../libcxx/function/TestLibCxxFunction.py | 52 + .../libcxx/function/main.cpp | 25 + .../libcxx/initializerlist/Makefile | 4 + .../initializerlist/TestInitializerList.py | 48 + .../libcxx/initializerlist/main.cpp | 21 + .../libcxx/iterator/Makefile | 7 + .../TestDataFormatterLibccIterator.py | 76 + .../libcxx/iterator/main.cpp | 42 + .../data-formatter-stl/libcxx/list/Makefile | 7 + .../list/TestDataFormatterLibcxxList.py | 215 + .../libcxx/list/loop/Makefile | 7 + .../loop/TestDataFormatterLibcxxListLoop.py | 73 + .../libcxx/list/loop/main.cpp | 30 + .../data-formatter-stl/libcxx/list/main.cpp | 43 + .../data-formatter-stl/libcxx/map/Makefile | 7 + .../libcxx/map/TestDataFormatterLibccMap.py | 314 + .../data-formatter-stl/libcxx/map/main.cpp | 77 + .../libcxx/multimap/Makefile | 7 + .../TestDataFormatterLibccMultiMap.py | 314 + .../libcxx/multimap/main.cpp | 77 + .../libcxx/multiset/Makefile | 7 + .../TestDataFormatterLibcxxMultiSet.py | 133 + .../libcxx/multiset/main.cpp | 57 + .../data-formatter-stl/libcxx/set/Makefile | 7 + .../libcxx/set/TestDataFormatterLibcxxSet.py | 128 + .../data-formatter-stl/libcxx/set/main.cpp | 57 + .../data-formatter-stl/libcxx/string/Makefile | 7 + .../string/TestDataFormatterLibcxxString.py | 100 + .../data-formatter-stl/libcxx/string/main.cpp | 15 + .../libcxx/unordered/Makefile | 7 + .../unordered/TestDataFormatterUnordered.py | 82 + .../libcxx/unordered/main.cpp | 84 + .../data-formatter-stl/libcxx/vbool/Makefile | 7 + .../vbool/TestDataFormatterLibcxxVBool.py | 78 + .../data-formatter-stl/libcxx/vbool/main.cpp | 70 + .../data-formatter-stl/libcxx/vector/Makefile | 7 + .../vector/TestDataFormatterLibcxxVector.py | 185 + .../data-formatter-stl/libcxx/vector/main.cpp | 35 + .../libstdcpp/iterator/Makefile | 15 + .../iterator/TestDataFormatterStdIterator.py | 74 + .../libstdcpp/iterator/main.cpp | 38 + .../libstdcpp/list/Makefile | 15 + .../list/TestDataFormatterStdList.py | 209 + .../libstdcpp/list/main.cpp | 34 + .../data-formatter-stl/libstdcpp/map/Makefile | 14 + .../libstdcpp/map/TestDataFormatterStdMap.py | 335 + .../data-formatter-stl/libstdcpp/map/main.cpp | 55 + .../libstdcpp/smart_ptr/Makefile | 15 + .../smart_ptr/TestDataFormatterStdSmartPtr.py | 49 + .../libstdcpp/smart_ptr/main.cpp | 20 + .../libstdcpp/string/Makefile | 15 + .../string/TestDataFormatterStdString.py | 81 + .../libstdcpp/string/main.cpp | 12 + .../libstdcpp/tuple/Makefile | 8 + .../tuple/TestDataFormatterStdTuple.py | 49 + .../libstdcpp/tuple/main.cpp | 9 + .../libstdcpp/unique_ptr/Makefile | 8 + .../TestDataFormatterStdUniquePtr.py | 96 + .../libstdcpp/unique_ptr/main.cpp | 35 + .../libstdcpp/vbool/Makefile | 8 + .../vbool/TestDataFormatterStdVBool.py | 82 + .../libstdcpp/vbool/main.cpp | 63 + .../libstdcpp/vector/Makefile | 15 + .../vector/TestDataFormatterStdVector.py | 217 + .../libstdcpp/vector/main.cpp | 31 + .../data-formatter-synth/Makefile | 12 + .../TestDataFormatterSynth.py | 220 + .../data-formatter-synth/main.cpp | 86 + .../data-formatter-synthtype/Makefile | 5 + .../TestDataFormatterSynthType.py | 58 + .../data-formatter-synthtype/main.cpp | 29 + .../myIntSynthProvider.py | 44 + .../data-formatter-synthval/Makefile | 5 + .../TestDataFormatterSynthVal.py | 122 + .../data-formatter-synthval/main.cpp | 41 + .../myIntSynthProvider.py | 44 + .../data-formatter/dump_dynamic/Makefile | 12 + .../dump_dynamic/TestDumpDynamic.py | 8 + .../data-formatter/dump_dynamic/main.cpp | 35 + .../format-propagation/Makefile | 5 + .../TestFormatPropagation.py | 85 + .../format-propagation/main.cpp | 13 + .../frameformat_smallstruct/Makefile | 5 + .../TestFrameFormatSmallStruct.py | 40 + .../frameformat_smallstruct/main.cpp | 25 + .../data-formatter/hexcaps/Makefile | 5 + .../hexcaps/TestDataFormatterHexCaps.py | 89 + .../data-formatter/hexcaps/main.cpp | 28 + .../language_category_updates/Makefile | 5 + ...estDataFormatterLanguageCategoryUpdates.py | 86 + .../language_category_updates/main.cpp | 20 + .../data-formatter/nsarraysynth/Makefile | 9 + .../nsarraysynth/TestNSArraySynthetic.py | 110 + .../data-formatter/nsarraysynth/main.m | 35 + .../data-formatter/nsdictionarysynth/Makefile | 9 + .../TestNSDictionarySynthetic.py | 124 + .../data-formatter/nsdictionarysynth/main.m | 30 + .../data-formatter/nssetsynth/Makefile | 9 + .../nssetsynth/TestNSSetSynthetic.py | 115 + .../data-formatter/nssetsynth/main.m | 34 + .../data-formatter/ostypeformatting/Makefile | 9 + .../ostypeformatting/TestFormattersOsType.py | 55 + .../data-formatter/ostypeformatting/main.mm | 23 + .../data-formatter/parray/Makefile | 5 + .../data-formatter/parray/TestPrintArray.py | 136 + .../data-formatter/parray/main.cpp | 29 + .../data-formatter/poarray/Makefile | 9 + .../poarray/TestPrintObjectArray.py | 112 + .../data-formatter/poarray/main.mm | 30 + .../data-formatter/ptr_ref_typedef/Makefile | 7 + .../ptr_ref_typedef/TestPtrRef2Typedef.py | 67 + .../data-formatter/ptr_ref_typedef/main.cpp | 19 + .../pyobjsynthprovider/Makefile | 5 + .../TestPyObjSynthProvider.py | 73 + .../pyobjsynthprovider/main.cpp | 20 + .../pyobjsynthprovider/provider.py | 16 + .../refpointer-recursion/Makefile | 5 + .../TestDataFormatterRefPtrRecursion.py | 43 + .../refpointer-recursion/main.cpp | 21 + .../setvaluefromcstring/Makefile | 4 + .../TestSetValueFromCString.py | 6 + .../data-formatter/setvaluefromcstring/main.m | 19 + .../data-formatter/stringprinter/Makefile | 12 + .../stringprinter/TestStringPrinter.py | 7 + .../data-formatter/stringprinter/main.cpp | 40 + .../summary-string-onfail/Makefile | 12 + .../Test-rdar-9974002.py | 147 + .../summary-string-onfail/main.cpp | 30 + .../data-formatter/synthcapping/Makefile | 5 + .../synthcapping/TestSyntheticCapping.py | 88 + .../synthcapping/fooSynthProvider.py | 27 + .../data-formatter/synthcapping/main.cpp | 62 + .../data-formatter/synthupdate/Makefile | 12 + .../TestSyntheticFilterRecompute.py | 87 + .../data-formatter/synthupdate/main.m | 25 + .../TestTypeSummaryListArg.py | 51 + .../type_summary_list_script/Makefile | 5 + .../TestTypeSummaryListScript.py | 65 + .../type_summary_list_script/main.cpp | 15 + .../tslsformatters.py | 12 + .../data-formatter/typedef_array/Makefile | 4 + .../typedef_array/TestTypedefArray.py | 7 + .../data-formatter/typedef_array/main.cpp | 14 + .../user-format-vs-summary/Makefile | 5 + .../TestUserFormatVsSummary.py | 74 + .../user-format-vs-summary/main.cpp | 20 + .../var-in-aggregate-misuse/Makefile | 11 + .../TestVarInAggregateMisuse.py | 80 + .../var-in-aggregate-misuse/main.cpp | 41 + .../varscript_formatting/Makefile | 5 + .../TestDataFormatterVarScriptFormatting.py | 60 + .../varscript_formatting/helperfunc.py | 6 + .../varscript_formatting/main.cpp | 8 + .../data-formatter/vector-types/Makefile | 5 + .../vector-types/TestVectorTypesFormatting.py | 90 + .../data-formatter/vector-types/main.cpp | 17 + .../test/functionalities/dead-strip/Makefile | 18 + .../dead-strip/TestDeadStrip.py | 68 + .../test/functionalities/dead-strip/cmds.txt | 4 + .../test/functionalities/dead-strip/main.c | 53 + .../test/functionalities/disassembly/Makefile | 5 + .../disassembly/TestDisassembleBreakpoint.py | 72 + .../disassembly/TestFrameDisassemble.py | 68 + .../test/functionalities/disassembly/main.cpp | 28 + .../dynamic_value_child_count/Makefile | 5 + .../TestDynamicValueChildCount.py | 84 + .../pass-to-base.cpp | 36 + .../embedded_interpreter/Makefile | 5 + .../TestConvenienceVariables.py | 108 + .../embedded_interpreter/main.c | 6 + .../test/functionalities/exec/Makefile | 5 + .../test/functionalities/exec/TestExec.py | 101 + .../test/functionalities/exec/main.cpp | 94 + .../expr-doesnt-deadlock/.categories | 1 + .../expr-doesnt-deadlock/Makefile | 6 + .../TestExprDoesntBlock.py | 65 + .../expr-doesnt-deadlock/locking.c | 80 + .../functionalities/fat_archives/Makefile | 14 + .../fat_archives/TestFatArchives.py | 61 + .../test/functionalities/fat_archives/a.c | 4 + .../test/functionalities/fat_archives/a.h | 1 + .../test/functionalities/fat_archives/main.c | 6 + .../test/functionalities/format/Makefile | 5 + .../functionalities/format/TestFormats.py | 65 + .../test/functionalities/format/main.c | 15 + .../frame-diagnose/array/Makefile | 5 + .../frame-diagnose/array/TestArray.py | 29 + .../frame-diagnose/array/main.c | 9 + .../frame-diagnose/bad-reference/Makefile | 5 + .../bad-reference/TestBadReference.py | 26 + .../frame-diagnose/bad-reference/main.cpp | 22 + .../complicated-expression/Makefile | 5 + .../TestComplicatedExpression.py | 29 + .../complicated-expression/main.c | 26 + .../dereference-argument/Makefile | 5 + .../TestDiagnoseDereferenceArgument.py | 29 + .../dereference-argument/main.c | 22 + .../dereference-function-return/Makefile | 5 + .../TestDiagnoseDereferenceFunctionReturn.py | 32 + .../dereference-function-return/main.c | 12 + .../frame-diagnose/dereference-this/Makefile | 5 + .../TestDiagnoseDereferenceThis.py | 29 + .../frame-diagnose/dereference-this/main.cpp | 15 + .../frame-diagnose/inheritance/Makefile | 5 + .../inheritance/TestDiagnoseInheritance.py | 26 + .../frame-diagnose/inheritance/main.cpp | 69 + .../frame-diagnose/local-variable/Makefile | 5 + .../local-variable/TestLocalVariable.py | 26 + .../frame-diagnose/local-variable/main.c | 4 + .../virtual-method-call/Makefile | 5 + ...estDiagnoseDereferenceVirtualMethodCall.py | 26 + .../virtual-method-call/main.cpp | 16 + .../functionalities/frame-language/Makefile | 12 + .../frame-language/TestGuessLanguage.py | 87 + .../functionalities/frame-language/main.cpp | 10 + .../frame-language/other-2.cpp | 7 + .../functionalities/frame-language/other.cpp | 10 + .../functionalities/frame-language/other.h | 7 + .../functionalities/frame-language/somefunc.c | 7 + .../test/functionalities/frame_var/Makefile | 6 + .../functionalities/frame_var/TestFrameVar.py | 99 + .../test/functionalities/frame_var/main.c | 11 + .../functionalities/frame_var_scope/Makefile | 3 + .../frame_var_scope/TestFrameVariableScope.py | 5 + .../functionalities/frame_var_scope/main.c | 21 + .../history/TestHistoryRecall.py | 45 + .../functionalities/inferior-assert/Makefile | 5 + .../inferior-assert/TestInferiorAssert.py | 314 + .../functionalities/inferior-assert/main.c | 19 + .../functionalities/inferior-changed/Makefile | 5 + .../inferior-changed/TestInferiorChanged.py | 84 + .../functionalities/inferior-changed/main.c | 16 + .../functionalities/inferior-changed/main2.c | 18 + .../inferior-crashing/Makefile | 5 + .../inferior-crashing/TestInferiorCrashing.py | 254 + .../functionalities/inferior-crashing/main.c | 18 + .../recursive-inferior/Makefile | 7 + .../TestRecursiveInferior.py | 245 + .../recursive-inferior/main.c | 19 + .../functionalities/inline-stepping/Makefile | 9 + .../inline-stepping/TestInlineStepping.py | 330 + .../inline-stepping/calling.cpp | 136 + .../functionalities/jitloader_gdb/Makefile | 5 + .../jitloader_gdb/TestJITLoaderGDB.py | 40 + .../test/functionalities/jitloader_gdb/main.c | 44 + .../launch_with_shellexpand/Makefile | 5 + .../TestLaunchWithShellExpand.py | 119 + .../launch_with_shellexpand/file1.txt | 0 .../launch_with_shellexpand/file2.txt | 0 .../launch_with_shellexpand/file3.txt | 0 .../launch_with_shellexpand/file4.txy | 0 .../launch_with_shellexpand/file5.tyx | 0 .../launch_with_shellexpand/foo bar | 0 .../launch_with_shellexpand/main.cpp | 5 + .../test/functionalities/load_unload/Makefile | 24 + .../load_unload/TestLoadUnload.py | 412 + .../test/functionalities/load_unload/a.cpp | 22 + .../test/functionalities/load_unload/a.mk | 23 + .../test/functionalities/load_unload/b.cpp | 21 + .../test/functionalities/load_unload/b.mk | 11 + .../test/functionalities/load_unload/c.cpp | 13 + .../test/functionalities/load_unload/c.mk | 11 + .../test/functionalities/load_unload/cmds.txt | 2 + .../test/functionalities/load_unload/d.cpp | 21 + .../test/functionalities/load_unload/d.mk | 13 + .../load_unload/hidden/Makefile | 11 + .../functionalities/load_unload/hidden/d.cpp | 21 + .../test/functionalities/load_unload/main.cpp | 80 + .../test/functionalities/longjmp/Makefile | 5 + .../functionalities/longjmp/TestLongjmp.py | 87 + .../test/functionalities/longjmp/main.c | 31 + .../functionalities/memory/cache/Makefile | 5 + .../memory/cache/TestMemoryCache.py | 66 + .../functionalities/memory/cache/main.cpp | 14 + .../test/functionalities/memory/find/Makefile | 5 + .../memory/find/TestMemoryFind.py | 71 + .../test/functionalities/memory/find/main.cpp | 17 + .../test/functionalities/memory/read/Makefile | 5 + .../memory/read/TestMemoryRead.py | 137 + .../test/functionalities/memory/read/main.cpp | 21 + .../test/functionalities/mtc/simple/Makefile | 6 + .../mtc/simple/TestMTCSimple.py | 57 + .../test/functionalities/mtc/simple/main.m | 15 + .../TestMultipleDebuggersCommands.py | 54 + .../functionalities/nested_alias/Makefile | 5 + .../nested_alias/TestNestedAlias.py | 93 + .../functionalities/nested_alias/main.cpp | 22 + .../non-overlapping-index-variable-i/Makefile | 5 + .../TestIndexVariable.py | 49 + .../non-overlapping-index-variable-i/main.cpp | 51 + .../test/functionalities/nosucharch/Makefile | 5 + .../nosucharch/TestNoSuchArch.py | 33 + .../test/functionalities/nosucharch/main.cpp | 3 + .../TestImageListMultiArchitecture.py | 48 + .../bin/hello-freebsd-10.0-x86_64-clang-3.3 | Bin 0 -> 7477 bytes .../bin/hello-freebsd-10.0-x86_64-gcc-4.7.3 | Bin 0 -> 7520 bytes .../bin/hello-netbsd-6.1-x86_64-gcc-4.5.3 | Bin 0 -> 7352 bytes .../hello-ubuntu-14.04-x86_64-clang-3.5pre | Bin 0 -> 8112 bytes .../bin/hello-ubuntu-14.04-x86_64-gcc-4.8.2 | Bin 0 -> 8056 bytes .../bin/hello-unknown-kalimba_arch4-kcc-36 | Bin 0 -> 17224 bytes .../bin/hello-unknown-kalimba_arch5-kcc-39 | Bin 0 -> 28356 bytes .../functionalities/object-file/bin/hello.c | 8 + .../functionalities/object-file/bin/hello.cpp | 8 + .../test/functionalities/paths/TestPaths.py | 52 + .../platform/TestPlatformCommand.py | 81 + .../functionalities/plugins/commands/Makefile | 8 + .../plugins/commands/TestPluginCommands.py | 69 + .../plugins/commands/plugin.cpp.template | 54 + .../plugins/python_os_plugin/Makefile | 3 + .../python_os_plugin/TestPythonOSPlugin.py | 197 + .../plugins/python_os_plugin/main.c | 7 + .../python_os_plugin/operating_system.py | 128 + .../python_os_plugin/operating_system2.py | 116 + .../postmortem/elf-core/TestLinuxCore.py | 271 + .../postmortem/elf-core/altmain.c | 6 + .../postmortem/elf-core/altmain.core | Bin 0 -> 40960 bytes .../postmortem/elf-core/altmain.out | Bin 0 -> 2330 bytes .../postmortem/elf-core/fpr_sse.cpp | 38 + .../postmortem/elf-core/gcore/TestGCore.py | 52 + .../postmortem/elf-core/gcore/linux-i386.core | Bin 0 -> 12324 bytes .../elf-core/gcore/linux-x86_64.core | Bin 0 -> 19008 bytes .../postmortem/elf-core/gcore/main.cpp | 63 + .../postmortem/elf-core/gcore/main.mk | 5 + .../postmortem/elf-core/gcore/make-core.sh | 56 + .../elf-core/linux-fpr_sse_i386.core | Bin 0 -> 32768 bytes .../elf-core/linux-fpr_sse_x86_64.core | Bin 0 -> 40960 bytes .../postmortem/elf-core/linux-i386.core | Bin 0 -> 28672 bytes .../postmortem/elf-core/linux-i386.out | Bin 0 -> 1971 bytes .../elf-core/linux-mips64el-gnuabi64.core | Bin 0 -> 24576 bytes .../elf-core/linux-mips64el-gnuabi64.out | Bin 0 -> 3576 bytes .../elf-core/linux-mips64el-gnuabin32.core | Bin 0 -> 28672 bytes .../elf-core/linux-mips64el-gnuabin32.out | Bin 0 -> 2792 bytes .../elf-core/linux-mipsel-gnuabio32.core | Bin 0 -> 28672 bytes .../elf-core/linux-mipsel-gnuabio32.out | Bin 0 -> 2872 bytes .../postmortem/elf-core/linux-s390x.core | Bin 0 -> 16384 bytes .../postmortem/elf-core/linux-s390x.out | Bin 0 -> 2824 bytes .../postmortem/elf-core/linux-x86_64.core | Bin 0 -> 40960 bytes .../postmortem/elf-core/linux-x86_64.out | Bin 0 -> 2575 bytes .../postmortem/elf-core/main.c | 17 + .../postmortem/elf-core/make-core.sh | 61 + .../thread_crash/TestLinuxCoreThreads.py | 61 + .../elf-core/thread_crash/linux-i386.core | Bin 0 -> 24576 bytes .../elf-core/thread_crash/linux-x86_64.core | Bin 0 -> 32768 bytes .../postmortem/elf-core/thread_crash/main.cpp | 63 + .../postmortem/elf-core/thread_crash/main.mk | 5 + .../elf-core/thread_crash/make-core.sh | 64 + .../minidump-new/TestMiniDumpNew.py | 169 + .../minidump-new/install_breakpad.cpp | 16 + .../postmortem/minidump-new/linux-x86_64 | Bin 0 -> 7279 bytes .../postmortem/minidump-new/linux-x86_64.cpp | 12 + .../postmortem/minidump-new/linux-x86_64.dmp | Bin 0 -> 63592 bytes .../minidump-new/linux-x86_64_not_crashed | Bin 0 -> 7675 bytes .../minidump-new/linux-x86_64_not_crashed.cpp | 22 + .../minidump-new/linux-x86_64_not_crashed.dmp | Bin 0 -> 63744 bytes .../postmortem/minidump-new/makefile.txt | 29 + .../postmortem/minidump/Makefile | 6 + .../postmortem/minidump/TestMiniDump.py | 126 + .../postmortem/minidump/fizzbuzz.cpp | 31 + .../postmortem/minidump/fizzbuzz_no_heap.dmp | Bin 0 -> 6297 bytes .../postmortem/minidump/main.cpp | 21 + .../wow64_minidump/TestWow64MiniDump.py | 73 + .../postmortem/wow64_minidump/fizzbuzz.cpp | 31 + .../wow64_minidump/fizzbuzz_wow64.dmp | Bin 0 -> 9280561 bytes .../functionalities/pre_run_dylibs/Makefile | 8 + .../pre_run_dylibs/TestPreRunDylibs.py | 38 + .../functionalities/pre_run_dylibs/foo.cpp | 3 + .../test/functionalities/pre_run_dylibs/foo.h | 6 + .../functionalities/pre_run_dylibs/main.cpp | 9 + .../functionalities/process_attach/Makefile | 7 + .../process_attach/TestProcessAttach.py | 62 + .../process_attach/attach_denied/Makefile | 7 + .../attach_denied/TestAttachDenied.py | 45 + .../process_attach/attach_denied/main.cpp | 108 + .../functionalities/process_attach/main.cpp | 20 + .../functionalities/process_group/Makefile | 5 + .../process_group/TestChangeProcessGroup.py | 89 + .../test/functionalities/process_group/main.c | 71 + .../functionalities/process_launch/Makefile | 7 + .../process_launch/TestProcessLaunch.py | 225 + .../process_launch/input-file.txt | 2 + .../functionalities/process_launch/main.cpp | 17 + .../process_launch/my_working_dir/.keep | 0 .../process_launch/print_cwd.cpp | 21 + .../process_launch/print_env.cpp | 10 + .../process_save_core/Makefile | 6 + .../process_save_core/TestProcessSaveCore.py | 67 + .../process_save_core/main.cpp | 21 + .../test/functionalities/ptr_refs/Makefile | 5 + .../functionalities/ptr_refs/TestPtrRefs.py | 49 + .../test/functionalities/ptr_refs/main.c | 27 + .../test/functionalities/recursion/Makefile | 5 + .../recursion/TestValueObjectRecursion.py | 69 + .../test/functionalities/recursion/main.cpp | 41 + .../register/intel_avx/Makefile | 7 + .../register/intel_avx/TestYMMRegister.py | 76 + .../functionalities/register/intel_avx/main.c | 67 + .../register/intel_xtended_registers/Makefile | 7 + .../TestMPXRegisters.py | 69 + .../register/intel_xtended_registers/main.cpp | 62 + .../mpx_bound_violation/Makefile | 7 + .../mpx_bound_violation/TestBoundViolation.py | 57 + .../mpx_bound_violation/main.cpp | 45 + .../register/register_command/Makefile | 5 + .../register_command/TestRegisters.py | 429 + .../register/register_command/a.cpp | 44 + .../register/register_command/main.cpp | 36 + .../test/functionalities/rerun/Makefile | 5 + .../test/functionalities/rerun/TestRerun.py | 63 + .../test/functionalities/rerun/main.cpp | 5 + .../functionalities/return-value/Makefile | 5 + .../return-value/TestReturnValue.py | 260 + .../functionalities/return-value/call-func.c | 407 + .../test/functionalities/set-data/Makefile | 7 + .../functionalities/set-data/TestSetData.py | 71 + .../test/functionalities/set-data/main.m | 19 + .../test/functionalities/signal/Makefile | 5 + .../functionalities/signal/TestSendSignal.py | 115 + .../signal/handle-segv/Makefile | 5 + .../signal/handle-segv/TestHandleSegv.py | 52 + .../functionalities/signal/handle-segv/main.c | 58 + .../test/functionalities/signal/main.c | 27 + .../functionalities/signal/raise/Makefile | 5 + .../functionalities/signal/raise/TestRaise.py | 279 + .../test/functionalities/signal/raise/main.c | 49 + .../single-quote-in-filename-to-lldb/Makefile | 5 + .../TestSingleQuoteInFilename.py | 77 + .../single-quote-in-filename-to-lldb/main.c | 7 + .../path with '09/.keep | 0 .../step-avoids-no-debug/Makefile | 8 + .../step-avoids-no-debug/TestStepNoDebug.py | 153 + .../step-avoids-no-debug/with-debug.c | 29 + .../step-avoids-no-debug/without-debug.c | 17 + .../test/functionalities/stop-hook/Makefile | 5 + .../stop-hook/TestStopHookCmd.py | 77 + .../stop-hook/TestStopHookMechanism.py | 127 + .../test/functionalities/stop-hook/main.cpp | 54 + .../stop-hook/multiple_threads/Makefile | 6 + .../TestStopHookMultipleThreads.py | 100 + .../stop-hook/multiple_threads/main.cpp | 77 + .../functionalities/target_command/Makefile | 8 + .../target_command/TestTargetCommand.py | 275 + .../test/functionalities/target_command/a.c | 16 + .../test/functionalities/target_command/b.c | 13 + .../test/functionalities/target_command/c.c | 29 + .../functionalities/target_command/globals.c | 25 + .../test/functionalities/testid/TestTestId.py | 17 + .../thread/backtrace_all/Makefile | 6 + .../thread/backtrace_all/ParallelTask.cpp | 151 + .../thread/backtrace_all/TestBacktraceAll.py | 67 + .../thread/break_after_join/Makefile | 5 + .../break_after_join/TestBreakAfterJoin.py | 95 + .../thread/break_after_join/main.cpp | 106 + .../Makefile | 9 + ...rrentBreakpointDelayBreakpointOneSignal.py | 23 + .../Makefile | 9 + ...rentBreakpointOneDelayBreakpointThreads.py | 22 + .../Makefile | 9 + ...eakpointsDelayedBreakpointOneWatchpoint.py | 25 + .../crash_with_break/Makefile | 9 + .../TestConcurrentCrashWithBreak.py | 21 + .../crash_with_signal/Makefile | 9 + .../TestConcurrentCrashWithSignal.py | 21 + .../crash_with_watchpoint/Makefile | 9 + .../TestConcurrentCrashWithWatchpoint.py | 22 + .../Makefile | 9 + ...rentCrashWithWatchpointBreakpointSignal.py | 25 + .../delay_signal_break/Makefile | 9 + .../TestConcurrentDelaySignalBreak.py | 23 + .../delay_signal_watch/Makefile | 9 + .../TestConcurrentDelaySignalWatch.py | 24 + .../delay_watch_break/Makefile | 9 + .../TestConcurrentDelayWatchBreak.py | 24 + .../Makefile | 9 + ...currentDelayedCrashWithBreakpointSignal.py | 23 + .../Makefile | 9 + ...entDelayedCrashWithBreakpointWatchpoint.py | 24 + .../thread/concurrent_events/main.cpp | 188 + .../many_breakpoints/Makefile | 9 + .../TestConcurrentManyBreakpoints.py | 23 + .../concurrent_events/many_crash/Makefile | 9 + .../many_crash/TestConcurrentManyCrash.py | 23 + .../concurrent_events/many_signals/Makefile | 9 + .../many_signals/TestConcurrentManySignals.py | 23 + .../many_watchpoints/Makefile | 9 + .../TestConcurrentManyWatchpoints.py | 23 + .../n_watch_n_break/Makefile | 9 + .../TestConcurrentNWatchNBreak.py | 23 + .../concurrent_events/signal_break/Makefile | 9 + .../signal_break/TestConcurrentSignalBreak.py | 21 + .../signal_delay_break/Makefile | 9 + .../TestConcurrentSignalDelayBreak.py | 23 + .../signal_delay_watch/Makefile | 9 + .../TestConcurrentSignalDelayWatch.py | 24 + .../signal_n_watch_n_break/Makefile | 9 + .../TestConcurrentSignalNWatchNBreak.py | 24 + .../concurrent_events/signal_watch/Makefile | 9 + .../signal_watch/TestConcurrentSignalWatch.py | 22 + .../signal_watch_break/Makefile | 9 + .../TestConcurrentSignalWatchBreak.py | 24 + .../two_breakpoint_threads/Makefile | 9 + .../TestConcurrentTwoBreakpointThreads.py | 21 + .../two_breakpoints_one_delay_signal/Makefile | 9 + ...tConcurrentTwoBreakpointsOneDelaySignal.py | 23 + .../two_breakpoints_one_signal/Makefile | 9 + .../TestConcurrentTwoBreakpointsOneSignal.py | 21 + .../two_breakpoints_one_watchpoint/Makefile | 9 + ...stConcurrentTwoBreakpointsOneWatchpoint.py | 24 + .../two_watchpoint_threads/Makefile | 9 + .../TestConcurrentTwoWatchpointThreads.py | 22 + .../two_watchpoints_one_breakpoint/Makefile | 9 + ...stConcurrentTwoWatchpointsOneBreakpoint.py | 24 + .../Makefile | 9 + ...currentTwoWatchpointsOneDelayBreakpoint.py | 24 + .../two_watchpoints_one_signal/Makefile | 9 + .../TestConcurrentTwoWatchpointsOneSignal.py | 22 + .../concurrent_events/watch_break/Makefile | 9 + .../watch_break/TestConcurrentWatchBreak.py | 24 + .../watch_break_delay/Makefile | 9 + .../TestConcurrentWatchBreakDelay.py | 24 + .../Makefile | 9 + ...tWatchpointDelayWatchpointOneBreakpoint.py | 24 + .../Makefile | 9 + ...entWatchpointWithDelayWatchpointThreads.py | 23 + .../thread/crash_during_step/Makefile | 4 + .../crash_during_step/TestCrashDuringStep.py | 64 + .../thread/crash_during_step/main.cpp | 16 + .../thread/create_after_attach/Makefile | 5 + .../TestCreateAfterAttach.py | 129 + .../thread/create_after_attach/main.cpp | 61 + .../thread/create_during_step/Makefile | 5 + .../TestCreateDuringStep.py | 154 + .../thread/create_during_step/main.cpp | 79 + .../thread/exit_during_break/Makefile | 5 + .../exit_during_break/TestExitDuringBreak.py | 72 + .../thread/exit_during_break/main.cpp | 118 + .../thread/exit_during_step/Makefile | 5 + .../exit_during_step/TestExitDuringStep.py | 150 + .../thread/exit_during_step/main.cpp | 78 + .../test/functionalities/thread/jump/Makefile | 5 + .../thread/jump/TestThreadJump.py | 79 + .../test/functionalities/thread/jump/main.cpp | 35 + .../functionalities/thread/jump/other.cpp | 13 + .../thread/multi_break/Makefile | 5 + .../multi_break/TestMultipleBreakpoints.py | 94 + .../thread/multi_break/main.cpp | 49 + .../thread/num_threads/Makefile | 5 + .../thread/num_threads/TestNumThreads.py | 121 + .../thread/num_threads/main.cpp | 62 + .../functionalities/thread/state/Makefile | 4 + .../thread/state/TestThreadStates.py | 327 + .../functionalities/thread/state/main.cpp | 45 + .../functionalities/thread/step_out/Makefile | 6 + .../thread/step_out/TestThreadStepOut.py | 179 + .../functionalities/thread/step_out/main.cpp | 51 + .../thread/step_until/Makefile | 5 + .../thread/step_until/TestStepUntil.py | 92 + .../functionalities/thread/step_until/main.c | 20 + .../thread/thread_exit/Makefile | 5 + .../thread/thread_exit/TestThreadExit.py | 122 + .../thread/thread_exit/main.cpp | 73 + .../thread/thread_specific_break/Makefile | 6 + .../TestThreadSpecificBreakpoint.py | 93 + .../thread/thread_specific_break/main.cpp | 20 + .../Makefile | 6 + .../TestThreadSpecificBpPlusCondition.py | 77 + .../main.cpp | 39 + .../test/functionalities/tsan/basic/Makefile | 6 + .../tsan/basic/TestTsanBasic.py | 136 + .../test/functionalities/tsan/basic/main.c | 37 + .../tsan/cpp_global_location/Makefile | 6 + .../TestTsanCPPGlobalLocation.py | 69 + .../tsan/cpp_global_location/main.cpp | 38 + .../tsan/global_location/Makefile | 6 + .../global_location/TestTsanGlobalLocation.py | 69 + .../tsan/global_location/main.c | 38 + .../functionalities/tsan/multiple/Makefile | 6 + .../tsan/multiple/TestTsanMultiple.py | 86 + .../test/functionalities/tsan/multiple/main.m | 138 + .../functionalities/tsan/thread_leak/Makefile | 6 + .../tsan/thread_leak/TestTsanThreadLeak.py | 48 + .../functionalities/tsan/thread_leak/main.c | 24 + .../tsan/thread_numbers/Makefile | 6 + .../thread_numbers/TestTsanThreadNumbers.py | 87 + .../tsan/thread_numbers/main.c | 58 + .../test/functionalities/tty/Makefile | 5 + .../test/functionalities/tty/TestTerminal.py | 52 + .../lldbsuite/test/functionalities/tty/main.c | 10 + .../functionalities/type_completion/Makefile | 12 + .../type_completion/TestTypeCompletion.py | 158 + .../functionalities/type_completion/main.cpp | 81 + .../test/functionalities/type_lookup/Makefile | 9 + .../type_lookup/TestTypeLookup.py | 55 + .../test/functionalities/type_lookup/main.mm | 58 + .../test/functionalities/ubsan/basic/Makefile | 6 + .../ubsan/basic/TestUbsanBasic.py | 90 + .../test/functionalities/ubsan/basic/main.c | 4 + .../ubsan/user-expression/Makefile | 6 + .../TestUbsanUserExpression.py | 49 + .../ubsan/user-expression/main.c | 9 + .../functionalities/unwind/ehframe/Makefile | 7 + .../unwind/ehframe/TestEhFrameUnwind.py | 52 + .../functionalities/unwind/ehframe/main.c | 46 + .../functionalities/unwind/noreturn/Makefile | 7 + .../unwind/noreturn/TestNoreturnUnwind.py | 86 + .../functionalities/unwind/noreturn/main.c | 35 + .../module-end/TestNoReturnModuleEnd.py | 53 + .../unwind/noreturn/module-end/a.s | 35 + .../unwind/noreturn/module-end/test.core | Bin 0 -> 40960 bytes .../unwind/noreturn/module-end/test.out | Bin 0 -> 520 bytes .../functionalities/unwind/sigtramp/Makefile | 5 + .../unwind/sigtramp/TestSigtrampUnwind.py | 94 + .../functionalities/unwind/sigtramp/main.c | 27 + .../functionalities/unwind/standard/Makefile | 3 + .../unwind/standard/TestStandardUnwind.py | 178 + .../unwind/standard/hand_written/divmod.cpp | 15 + .../unwind/standard/hand_written/fprintf.cpp | 16 + .../standard/hand_written/new_delete.cpp | 15 + .../functionalities/value_md5_crash/Makefile | 5 + .../value_md5_crash/TestValueMD5Crash.py | 55 + .../functionalities/value_md5_crash/main.cpp | 29 + .../watchpoint/hello_watchlocation/Makefile | 6 + .../hello_watchlocation/TestWatchLocation.py | 122 + .../watchpoint/hello_watchlocation/main.cpp | 104 + .../watchpoint/hello_watchpoint/Makefile | 5 + .../hello_watchpoint/TestMyFirstWatchpoint.py | 101 + .../watchpoint/hello_watchpoint/main.c | 30 + .../multi_watchpoint_slots/Makefile | 5 + .../TestWatchpointMultipleSlots.py | 97 + .../watchpoint/multi_watchpoint_slots/main.c | 29 + .../watchpoint/multiple_hits/Makefile | 5 + .../multiple_hits/TestMultipleHits.py | 58 + .../watchpoint/multiple_hits/main.cpp | 29 + .../watchpoint/multiple_threads/Makefile | 6 + .../TestWatchpointMultipleThreads.py | 166 + .../watchpoint/multiple_threads/main.cpp | 79 + .../watchpoint/step_over_watchpoint/Makefile | 5 + .../TestStepOverWatchpoint.py | 125 + .../watchpoint/step_over_watchpoint/main.c | 19 + .../watchpoint/variable_out_of_scope/Makefile | 5 + .../TestWatchedVarHitWhenInScope.py | 88 + .../watchpoint/variable_out_of_scope/main.c | 15 + .../watchpoint/watchpoint_commands/Makefile | 5 + .../TestWatchpointCommands.py | 387 + .../watchpoint_commands/command/Makefile | 5 + .../command/TestWatchpointCommandLLDB.py | 175 + .../command/TestWatchpointCommandPython.py | 172 + .../watchpoint_commands/command/main.cpp | 28 + .../command/watchpoint_command.py | 15 + .../watchpoint_commands/condition/Makefile | 5 + .../condition/TestWatchpointConditionCmd.py | 98 + .../watchpoint_commands/condition/main.cpp | 28 + .../watchpoint/watchpoint_commands/main.c | 24 + .../watchpoint/watchpoint_disable/Makefile | 5 + .../TestWatchpointDisable.py | 88 + .../watchpoint/watchpoint_disable/main.c | 13 + .../watchpoint/watchpoint_events/Makefile | 5 + .../watchpoint_events/TestWatchpointEvents.py | 120 + .../watchpoint/watchpoint_events/main.c | 9 + .../watchpoint/watchpoint_on_vectors/Makefile | 5 + .../TestValueOfVectorVariable.py | 54 + .../watchpoint/watchpoint_on_vectors/main.c | 16 + .../watchpoint_set_command/Makefile | 6 + .../TestWatchLocationWithWatchSet.py | 110 + .../TestWatchpointSetErrorCases.py | 74 + .../watchpoint_set_command/main.cpp | 121 + .../watchpoint/watchpoint_size/Makefile | 5 + .../watchpoint_size/TestWatchpointSizes.py | 140 + .../watchpoint/watchpoint_size/main.c | 66 + .../Python/lldbsuite/test/help/TestApropos.py | 28 + .../Python/lldbsuite/test/help/TestHelp.py | 232 + .../test/issue_verification/Makefile | 4 + .../test/issue_verification/README.txt | 5 + .../TestExpectedTimeout.py.park | 20 + .../test/issue_verification/TestFail.py.park | 16 + .../TestInvalidDecorator.py.park | 13 + .../issue_verification/TestRerunFail.py.park | 23 + .../TestRerunFileLevelTimeout.py.park | 33 + .../TestRerunInline.py.park | 13 + .../TestRerunTimeout.py.park | 24 + .../issue_verification/TestSignal.py.park | 26 + .../TestSignalOutsideTestMethod.py.park | 24 + .../issue_verification/TestTimeout.py.park | 19 + .../test/issue_verification/disable.py | 20 + .../test/issue_verification/enable.py | 20 + .../inline_rerun_inferior.cpp | 14 + .../test/issue_verification/rerun_base.py | 28 + .../lldbsuite/test/lang/c/anonymous/Makefile | 5 + .../test/lang/c/anonymous/TestAnonymous.py | 174 + .../lldbsuite/test/lang/c/anonymous/main.c | 82 + .../test/lang/c/array_types/Makefile | 5 + .../test/lang/c/array_types/TestArrayTypes.py | 228 + .../test/lang/c/array_types/cmds.txt | 3 + .../lldbsuite/test/lang/c/array_types/main.c | 51 + .../lldbsuite/test/lang/c/bitfields/Makefile | 5 + .../test/lang/c/bitfields/TestBitfields.py | 188 + .../lldbsuite/test/lang/c/bitfields/main.c | 81 + .../lldbsuite/test/lang/c/blocks/Makefile | 6 + .../test/lang/c/blocks/TestBlocks.py | 84 + .../lldbsuite/test/lang/c/blocks/main.c | 21 + .../test/lang/c/conflicting-symbol/Makefile | 18 + .../test/lang/c/conflicting-symbol/One.mk | 12 + .../test/lang/c/conflicting-symbol/One/One.c | 6 + .../test/lang/c/conflicting-symbol/One/One.h | 4 + .../c/conflicting-symbol/One/OneConstant.c | 1 + .../TestConflictingSymbol.py | 90 + .../test/lang/c/conflicting-symbol/Two.mk | 12 + .../test/lang/c/conflicting-symbol/Two/Two.c | 6 + .../test/lang/c/conflicting-symbol/Two/Two.h | 4 + .../c/conflicting-symbol/Two/TwoConstant.c | 1 + .../test/lang/c/conflicting-symbol/main.c | 11 + .../test/lang/c/const_variables/Makefile | 7 + .../c/const_variables/TestConstVariables.py | 76 + .../test/lang/c/const_variables/functions.c | 18 + .../test/lang/c/const_variables/main.c | 23 + .../lldbsuite/test/lang/c/enum_types/Makefile | 5 + .../test/lang/c/enum_types/TestEnumTypes.py | 105 + .../lldbsuite/test/lang/c/enum_types/main.c | 40 + .../test/lang/c/find_struct_type/Makefile | 3 + .../c/find_struct_type/TestFindStructTypes.py | 67 + .../test/lang/c/find_struct_type/main.c | 25 + .../lldbsuite/test/lang/c/forward/Makefile | 5 + .../lldbsuite/test/lang/c/forward/README.txt | 5 + .../lang/c/forward/TestForwardDeclaration.py | 55 + .../lldbsuite/test/lang/c/forward/foo.c | 8 + .../lldbsuite/test/lang/c/forward/foo.h | 4 + .../lldbsuite/test/lang/c/forward/main.c | 18 + .../test/lang/c/function_types/Makefile | 5 + .../c/function_types/TestFunctionTypes.py | 85 + .../test/lang/c/function_types/main.c | 22 + .../test/lang/c/global_variables/Makefile | 8 + .../c/global_variables/TestGlobalVariables.py | 103 + .../test/lang/c/global_variables/a.c | 15 + .../test/lang/c/global_variables/cmds.txt | 3 + .../test/lang/c/global_variables/main.c | 24 + .../c/inlines/TestRedefinitionsInInlines.py | 11 + .../lldbsuite/test/lang/c/inlines/main.c | 24 + .../lldbsuite/test/lang/c/modules/Makefile | 5 + .../test/lang/c/modules/TestCModules.py | 80 + .../lldbsuite/test/lang/c/modules/main.c | 20 + .../lldbsuite/test/lang/c/recurse/Makefile | 5 + .../lldbsuite/test/lang/c/recurse/main.c | 28 + .../test/lang/c/register_variables/Makefile | 7 + .../TestRegisterVariables.py | 206 + .../test/lang/c/register_variables/test.c | 44 + .../lldbsuite/test/lang/c/set_values/Makefile | 5 + .../test/lang/c/set_values/TestSetValues.py | 142 + .../lldbsuite/test/lang/c/set_values/main.c | 116 + .../lldbsuite/test/lang/c/shared_lib/Makefile | 8 + .../test/lang/c/shared_lib/TestSharedLib.py | 99 + .../lldbsuite/test/lang/c/shared_lib/foo.c | 22 + .../lldbsuite/test/lang/c/shared_lib/foo.h | 10 + .../lldbsuite/test/lang/c/shared_lib/main.c | 13 + .../c/shared_lib_stripped_symbols/Makefile | 10 + .../TestSharedLibStrippedSymbols.py | 89 + .../lang/c/shared_lib_stripped_symbols/foo.c | 22 + .../lang/c/shared_lib_stripped_symbols/foo.h | 12 + .../lang/c/shared_lib_stripped_symbols/main.c | 13 + .../test/lang/c/step-target/Makefile | 5 + .../test/lang/c/step-target/TestStepTarget.py | 125 + .../lldbsuite/test/lang/c/step-target/main.c | 40 + .../lldbsuite/test/lang/c/stepping/Makefile | 5 + .../lang/c/stepping/TestStepAndBreakpoints.py | 301 + .../lang/c/stepping/TestThreadStepping.py | 87 + .../lldbsuite/test/lang/c/stepping/main.c | 69 + .../lldbsuite/test/lang/c/strings/Makefile | 5 + .../test/lang/c/strings/TestCStrings.py | 57 + .../lldbsuite/test/lang/c/strings/main.c | 18 + .../test/lang/c/struct_types/Makefile | 3 + .../lang/c/struct_types/TestStructTypes.py | 7 + .../lldbsuite/test/lang/c/struct_types/main.c | 43 + .../test/lang/c/tls_globals/Makefile | 11 + .../test/lang/c/tls_globals/TestTlsGlobals.py | 95 + .../lldbsuite/test/lang/c/tls_globals/a.c | 24 + .../lldbsuite/test/lang/c/tls_globals/main.c | 42 + .../lldbsuite/test/lang/c/typedef/Makefile | 5 + .../test/lang/c/typedef/Testtypedef.py | 55 + .../lldbsuite/test/lang/c/typedef/main.c | 46 + .../lldbsuite/test/lang/c/unions/Makefile | 5 + .../test/lang/c/unions/TestUnionMembers.py | 54 + .../lldbsuite/test/lang/c/unions/main.c | 18 + .../lldbsuite/test/lang/cpp/auto/Makefile | 7 + .../test/lang/cpp/auto/TestCPPAuto.py | 40 + .../lldbsuite/test/lang/cpp/auto/main.cpp | 16 + .../lldbsuite/test/lang/cpp/bool/Makefile | 5 + .../test/lang/cpp/bool/TestCPPBool.py | 28 + .../lldbsuite/test/lang/cpp/bool/main.cpp | 17 + .../lang/cpp/breakpoint-commands/Makefile | 5 + .../TestCPPBreakpointCommands.py | 86 + .../lang/cpp/breakpoint-commands/nested.cpp | 76 + .../test/lang/cpp/call-function/Makefile | 5 + .../cpp/call-function/TestCallCPPFunction.py | 38 + .../test/lang/cpp/call-function/main.cpp | 11 + .../test/lang/cpp/chained-calls/Makefile | 5 + .../cpp/chained-calls/TestCppChainedCalls.py | 102 + .../test/lang/cpp/chained-calls/main.cpp | 33 + .../test/lang/cpp/char1632_t/.categories | 1 + .../test/lang/cpp/char1632_t/Makefile | 8 + .../test/lang/cpp/char1632_t/TestChar1632T.py | 122 + .../test/lang/cpp/char1632_t/main.cpp | 44 + .../class-template-parameter-pack/Makefile | 3 + .../TestClassTemplateParameterPack.py | 9 + .../class-template-parameter-pack/main.cpp | 61 + .../test/lang/cpp/class_static/Makefile | 5 + .../cpp/class_static/TestStaticVariables.py | 132 + .../test/lang/cpp/class_static/main.cpp | 53 + .../test/lang/cpp/class_types/Makefile | 5 + .../lang/cpp/class_types/TestClassTypes.py | 224 + .../class_types/TestClassTypesDisassembly.py | 100 + .../test/lang/cpp/class_types/cmds.txt | 3 + .../test/lang/cpp/class_types/main.cpp | 126 + .../test/lang/cpp/const_this/Makefile | 8 + .../test/lang/cpp/const_this/TestConstThis.py | 4 + .../test/lang/cpp/const_this/main.cpp | 23 + .../lldbsuite/test/lang/cpp/diamond/Makefile | 5 + .../test/lang/cpp/diamond/TestDiamond.py | 51 + .../lldbsuite/test/lang/cpp/diamond/main.cpp | 85 + .../test/lang/cpp/dynamic-value/Makefile | 5 + .../cpp/dynamic-value/TestCppValueCast.py | 139 + .../cpp/dynamic-value/TestDynamicValue.py | 253 + .../lang/cpp/dynamic-value/pass-to-base.cpp | 69 + .../lang/cpp/dynamic-value/sbvalue-cast.cpp | 80 + .../test/lang/cpp/enum_types/Makefile | 10 + .../lang/cpp/enum_types/TestCPP11EnumTypes.py | 130 + .../test/lang/cpp/enum_types/main.cpp | 33 + .../test/lang/cpp/exceptions/Makefile | 5 + .../exceptions/TestCPPExceptionBreakpoints.py | 84 + .../test/lang/cpp/exceptions/exceptions.cpp | 42 + .../lldbsuite/test/lang/cpp/extern_c/Makefile | 3 + .../lang/cpp/extern_c/TestExternCSymbols.py | 4 + .../lldbsuite/test/lang/cpp/extern_c/main.cpp | 29 + .../lang/cpp/frame-var-anon-unions/Makefile | 5 + .../TestFrameVariableAnonymousUnions.py | 35 + .../lang/cpp/frame-var-anon-unions/main.cpp | 23 + .../function-template-parameter-pack/Makefile | 3 + .../TestFunctionTemplateParameterPack.py | 6 + .../function-template-parameter-pack/main.cpp | 24 + .../test/lang/cpp/global_operators/Makefile | 5 + .../TestCppGlobalOperators.py | 97 + .../test/lang/cpp/global_operators/main.cpp | 42 + .../lldbsuite/test/lang/cpp/gmodules/Makefile | 7 + .../cpp/gmodules/TestWithModuleDebugging.py | 71 + .../lldbsuite/test/lang/cpp/gmodules/main.cpp | 5 + .../lldbsuite/test/lang/cpp/gmodules/pch.h | 12 + .../test/lang/cpp/incomplete-types/Makefile | 35 + .../TestCppIncompleteTypes.py | 83 + .../test/lang/cpp/incomplete-types/a.cpp | 10 + .../test/lang/cpp/incomplete-types/a.h | 11 + .../test/lang/cpp/incomplete-types/length.cpp | 8 + .../test/lang/cpp/incomplete-types/length.h | 8 + .../test/lang/cpp/incomplete-types/main.cpp | 18 + .../lldbsuite/test/lang/cpp/inlines/Makefile | 5 + .../test/lang/cpp/inlines/TestInlines.py | 62 + .../test/lang/cpp/inlines/inlines.cpp | 53 + .../lldbsuite/test/lang/cpp/inlines/inlines.h | 4 + .../test/lang/cpp/lambdas/TestLambdas.py | 7 + .../lldbsuite/test/lang/cpp/lambdas/main.cpp | 17 + .../test/lang/cpp/limit-debug-info/Makefile | 7 + .../TestWithLimitDebugInfo.py | 65 + .../test/lang/cpp/limit-debug-info/base.cpp | 6 + .../test/lang/cpp/limit-debug-info/base.h | 10 + .../lang/cpp/limit-debug-info/derived.cpp | 6 + .../test/lang/cpp/limit-debug-info/derived.h | 13 + .../test/lang/cpp/limit-debug-info/main.cpp | 7 + .../test/lang/cpp/llvm-style/Makefile | 3 + .../test/lang/cpp/llvm-style/TestLLVMStyle.py | 7 + .../test/lang/cpp/llvm-style/main.cpp | 36 + .../Makefile | 5 + .../TestMembersAndLocalsWithSameName.py | 247 + .../main.cpp | 73 + .../test/lang/cpp/namespace/Makefile | 5 + .../test/lang/cpp/namespace/TestNamespace.py | 239 + .../lang/cpp/namespace/TestNamespaceLookup.py | 324 + .../test/lang/cpp/namespace/cmds.txt | 3 + .../test/lang/cpp/namespace/main.cpp | 124 + .../lldbsuite/test/lang/cpp/namespace/ns.cpp | 32 + .../lldbsuite/test/lang/cpp/namespace/ns.h | 36 + .../lldbsuite/test/lang/cpp/namespace/ns2.cpp | 65 + .../lldbsuite/test/lang/cpp/namespace/ns3.cpp | 27 + .../lang/cpp/namespace_conflicts/Makefile | 3 + .../TestNamespaceConflicts.py | 7 + .../lang/cpp/namespace_conflicts/main.cpp | 29 + .../lang/cpp/namespace_definitions/Makefile | 19 + .../TestNamespaceDefinitions.py | 73 + .../test/lang/cpp/namespace_definitions/a.cpp | 16 + .../test/lang/cpp/namespace_definitions/a.mk | 9 + .../test/lang/cpp/namespace_definitions/b.cpp | 12 + .../test/lang/cpp/namespace_definitions/b.mk | 9 + .../test/lang/cpp/namespace_definitions/foo.h | 18 + .../lang/cpp/namespace_definitions/main.cpp | 16 + .../lldbsuite/test/lang/cpp/nsimport/Makefile | 5 + .../test/lang/cpp/nsimport/TestCppNsImport.py | 139 + .../lldbsuite/test/lang/cpp/nsimport/main.cpp | 72 + .../lang/cpp/overloaded-functions/Makefile | 5 + .../TestOverloadedFunctions.py | 41 + .../lang/cpp/overloaded-functions/main.cpp | 43 + .../cpp/overloaded-functions/static-a.cpp | 9 + .../cpp/overloaded-functions/static-b.cpp | 9 + .../test/lang/cpp/printf/TestPrintf.py | 7 + .../lldbsuite/test/lang/cpp/printf/main.cpp | 21 + .../test/lang/cpp/rvalue-references/Makefile | 7 + .../rvalue-references/TestRvalueReferences.py | 56 + .../test/lang/cpp/rvalue-references/main.cpp | 12 + .../lldbsuite/test/lang/cpp/scope/Makefile | 5 + .../test/lang/cpp/scope/TestCppScope.py | 98 + .../lldbsuite/test/lang/cpp/scope/main.cpp | 25 + .../test/lang/cpp/signed_types/Makefile | 5 + .../lang/cpp/signed_types/TestSignedTypes.py | 68 + .../test/lang/cpp/signed_types/main.cpp | 33 + .../test/lang/cpp/static_members/Makefile | 5 + .../static_members/TestCPPStaticMembers.py | 62 + .../test/lang/cpp/static_members/main.cpp | 36 + .../test/lang/cpp/static_methods/Makefile | 5 + .../static_methods/TestCPPStaticMethods.py | 39 + .../test/lang/cpp/static_methods/main.cpp | 38 + .../lldbsuite/test/lang/cpp/stl/Makefile | 15 + .../lldbsuite/test/lang/cpp/stl/TestSTL.py | 129 + .../lang/cpp/stl/TestStdCXXDisassembly.py | 118 + .../lldbsuite/test/lang/cpp/stl/cmds.txt | 3 + .../lldbsuite/test/lang/cpp/stl/main.cpp | 30 + .../lldbsuite/test/lang/cpp/symbols/Makefile | 3 + .../test/lang/cpp/symbols/TestSymbols.py | 7 + .../lldbsuite/test/lang/cpp/symbols/main.cpp | 40 + .../lldbsuite/test/lang/cpp/template/Makefile | 7 + .../lang/cpp/template/TestTemplateArgs.py | 131 + .../lldbsuite/test/lang/cpp/template/main.cpp | 72 + .../lldbsuite/test/lang/cpp/this/Makefile | 5 + .../test/lang/cpp/this/TestCPPThis.py | 60 + .../lldbsuite/test/lang/cpp/this/main.cpp | 53 + .../test/lang/cpp/unicode-literals/Makefile | 8 + .../unicode-literals/TestUnicodeLiterals.py | 95 + .../test/lang/cpp/unicode-literals/main.cpp | 21 + .../test/lang/cpp/unique-types/Makefile | 5 + .../lang/cpp/unique-types/TestUniqueTypes.py | 70 + .../test/lang/cpp/unique-types/main.cpp | 24 + .../test/lang/cpp/unsigned_types/Makefile | 5 + .../cpp/unsigned_types/TestUnsignedTypes.py | 64 + .../test/lang/cpp/unsigned_types/main.cpp | 22 + .../lldbsuite/test/lang/cpp/virtual/Makefile | 5 + .../test/lang/cpp/virtual/TestVirtual.py | 102 + .../lldbsuite/test/lang/cpp/virtual/main.cpp | 116 + .../test/lang/cpp/wchar_t/.categories | 1 + .../lldbsuite/test/lang/cpp/wchar_t/Makefile | 8 + .../test/lang/cpp/wchar_t/TestCxxWCharT.py | 80 + .../lldbsuite/test/lang/cpp/wchar_t/main.cpp | 35 + .../lang/go/expressions/TestExpressions.py | 122 + .../test/lang/go/expressions/main.go | 21 + .../lang/go/formatters/TestGoFormatters.py | 76 + .../lldbsuite/test/lang/go/formatters/main.go | 9 + .../test/lang/go/goroutines/TestGoroutines.py | 104 + .../lldbsuite/test/lang/go/goroutines/main.go | 89 + .../lang/go/runtime/TestGoLanguageRuntime | 80 + .../lldbsuite/test/lang/go/runtime/main.go | 38 + .../test/lang/go/types/TestGoASTContext.py | 145 + .../lldbsuite/test/lang/go/types/main.go | 47 + .../Python/lldbsuite/test/lang/mixed/Makefile | 6 + .../test/lang/mixed/TestMixedLanguages.py | 60 + .../Python/lldbsuite/test/lang/mixed/foo.cpp | 11 + .../Python/lldbsuite/test/lang/mixed/main.c | 15 + .../lldbsuite/test/lang/objc/.categories | 1 + .../objc/bitfield_ivars/TestBitfieldIvars.py | 12 + .../test/lang/objc/bitfield_ivars/main.m | 52 + .../lldbsuite/test/lang/objc/blocks/Makefile | 6 + .../lang/objc/blocks/TestObjCIvarsInBlocks.py | 135 + .../test/lang/objc/blocks/ivars-in-blocks.h | 11 + .../test/lang/objc/blocks/ivars-in-blocks.m | 57 + .../lldbsuite/test/lang/objc/blocks/main.m | 10 + .../lang/objc/conflicting-definition/Makefile | 24 + .../objc/conflicting-definition/Test/Foo.h | 9 + .../objc/conflicting-definition/Test/Test.h | 10 + .../objc/conflicting-definition/Test/Test.m | 8 + .../TestConflictingDefinition.py | 49 + .../objc/conflicting-definition/TestExt/Foo.h | 9 + .../conflicting-definition/TestExt/TestExt.h | 7 + .../conflicting-definition/TestExt/TestExt.m | 8 + .../lang/objc/conflicting-definition/main.m | 10 + .../test/lang/objc/forward-decl/Container.h | 13 + .../test/lang/objc/forward-decl/Container.m | 27 + .../test/lang/objc/forward-decl/Makefile | 9 + .../lang/objc/forward-decl/TestForwardDecl.py | 59 + .../test/lang/objc/forward-decl/main.m | 14 + .../test/lang/objc/foundation/Makefile | 8 + .../lang/objc/foundation/TestConstStrings.py | 60 + .../foundation/TestFoundationDisassembly.py | 162 + .../lang/objc/foundation/TestObjCMethods.py | 327 + .../lang/objc/foundation/TestObjCMethods2.py | 205 + .../foundation/TestObjectDescriptionAPI.py | 78 + .../lang/objc/foundation/TestRuntimeTypes.py | 62 + .../lang/objc/foundation/TestSymbolTable.py | 74 + .../test/lang/objc/foundation/const-strings.m | 24 + .../test/lang/objc/foundation/main.m | 141 + .../test/lang/objc/foundation/my-base.h | 8 + .../test/lang/objc/foundation/my-base.m | 10 + .../test/lang/objc/global_ptrs/Makefile | 6 + .../objc/global_ptrs/TestGlobalObjects.py | 60 + .../test/lang/objc/global_ptrs/main.m | 11 + .../lang/objc/hidden-ivars/InternalDefiner.h | 11 + .../lang/objc/hidden-ivars/InternalDefiner.m | 31 + .../test/lang/objc/hidden-ivars/Makefile | 9 + .../lang/objc/hidden-ivars/TestHiddenIvars.py | 237 + .../test/lang/objc/hidden-ivars/main.m | 54 + .../test/lang/objc/ivar-IMP/Makefile | 12 + .../lang/objc/ivar-IMP/TestObjCiVarIMP.py | 66 + .../test/lang/objc/ivar-IMP/myclass.h | 6 + .../test/lang/objc/ivar-IMP/myclass.m | 16 + .../lldbsuite/test/lang/objc/ivar-IMP/repro.m | 7 + .../lang/objc/modules-auto-import/Makefile | 6 + .../TestModulesAutoImport.py | 53 + .../test/lang/objc/modules-auto-import/main.m | 7 + .../lang/objc/modules-incomplete/Makefile | 8 + .../TestIncompleteModules.py | 67 + .../test/lang/objc/modules-incomplete/main.m | 11 + .../lang/objc/modules-incomplete/module.map | 4 + .../lang/objc/modules-incomplete/myModule.h | 8 + .../lang/objc/modules-incomplete/myModule.m | 14 + .../objc/modules-inline-functions/Makefile | 9 + .../TestModulesInlineFunctions.py | 61 + .../lang/objc/modules-inline-functions/main.m | 9 + .../objc/modules-inline-functions/module.map | 4 + .../objc/modules-inline-functions/myModule.c | 7 + .../objc/modules-inline-functions/myModule.h | 7 + .../lldbsuite/test/lang/objc/modules/Makefile | 7 + .../test/lang/objc/modules/TestObjCModules.py | 84 + .../lldbsuite/test/lang/objc/modules/main.m | 12 + .../lldbsuite/test/lang/objc/objc++/Makefile | 6 + .../test/lang/objc/objc++/TestObjCXX.py | 36 + .../lldbsuite/test/lang/objc/objc++/main.mm | 19 + .../lang/objc/objc-baseclass-sbtype/Makefile | 6 + .../TestObjCBaseClassSBType.py | 68 + .../lang/objc/objc-baseclass-sbtype/main.m | 22 + .../lang/objc/objc-builtin-types/Makefile | 5 + .../TestObjCBuiltinTypes.py | 64 + .../lang/objc/objc-builtin-types/main.cpp | 9 + .../test/lang/objc/objc-checker/Makefile | 6 + .../objc/objc-checker/TestObjCCheckers.py | 79 + .../test/lang/objc/objc-checker/main.m | 32 + .../test/lang/objc/objc-class-method/Makefile | 6 + .../objc-class-method/TestObjCClassMethod.py | 64 + .../test/lang/objc/objc-class-method/class.m | 24 + .../lang/objc/objc-dyn-sbtype/.categories | 1 + .../test/lang/objc/objc-dyn-sbtype/Makefile | 7 + .../objc-dyn-sbtype/TestObjCDynamicSBType.py | 93 + .../test/lang/objc/objc-dyn-sbtype/main.m | 53 + .../lang/objc/objc-dynamic-value/Makefile | 6 + .../TestObjCDynamicValue.py | 211 + .../objc/objc-dynamic-value/dynamic-value.m | 147 + .../test/lang/objc/objc-ivar-offsets/Makefile | 6 + .../objc-ivar-offsets/TestObjCIvarOffsets.py | 86 + .../test/lang/objc/objc-ivar-offsets/main.m | 15 + .../objc-ivar-offsets/objc-ivar-offsets.h | 27 + .../objc-ivar-offsets/objc-ivar-offsets.m | 19 + .../objc-ivar-protocols/TestIvarProtocols.py | 6 + .../test/lang/objc/objc-ivar-protocols/main.m | 33 + .../lang/objc/objc-ivar-stripped/Makefile | 15 + .../TestObjCIvarStripped.py | 70 + .../test/lang/objc/objc-ivar-stripped/main.m | 33 + .../test/lang/objc/objc-new-syntax/Makefile | 7 + .../objc/objc-new-syntax/TestObjCNewSyntax.py | 264 + .../test/lang/objc/objc-new-syntax/main.m | 21 + .../test/lang/objc/objc-optimized/Makefile | 8 + .../objc/objc-optimized/TestObjcOptimized.py | 76 + .../test/lang/objc/objc-optimized/main.m | 44 + .../test/lang/objc/objc-property/Makefile | 6 + .../objc/objc-property/TestObjCProperty.py | 139 + .../test/lang/objc/objc-property/main.m | 113 + .../lang/objc/objc-runtime-ivars/Makefile | 6 + .../objc-runtime-ivars/TestRuntimeIvars.py | 6 + .../test/lang/objc/objc-runtime-ivars/main.m | 10 + .../objc/objc-static-method-stripped/Makefile | 16 + .../TestObjCStaticMethodStripped.py | 80 + .../objc/objc-static-method-stripped/static.m | 29 + .../lang/objc/objc-static-method/Makefile | 6 + .../TestObjCStaticMethod.py | 75 + .../lang/objc/objc-static-method/static.m | 29 + .../test/lang/objc/objc-stepping/Makefile | 6 + .../objc/objc-stepping/TestObjCStepping.py | 224 + .../lang/objc/objc-stepping/stepping-tests.m | 138 + .../lang/objc/objc-struct-argument/Makefile | 6 + .../TestObjCStructArgument.py | 68 + .../lang/objc/objc-struct-argument/test.m | 34 + .../lang/objc/objc-struct-return/Makefile | 6 + .../TestObjCStructReturn.py | 62 + .../test/lang/objc/objc-struct-return/test.m | 23 + .../test/lang/objc/objc-super/Makefile | 6 + .../lang/objc/objc-super/TestObjCSuper.py | 67 + .../test/lang/objc/objc-super/class.m | 39 + .../test/lang/objc/print-obj/Makefile | 6 + .../test/lang/objc/print-obj/TestPrintObj.py | 93 + .../test/lang/objc/print-obj/blocked.m | 73 + .../test/lang/objc/ptr_refs/Makefile | 5 + .../lang/objc/ptr_refs/TestPtrRefsObjC.py | 50 + .../lldbsuite/test/lang/objc/ptr_refs/main.m | 39 + .../test/lang/objc/radar-9691614/Makefile | 7 + .../TestObjCMethodReturningBOOL.py | 48 + .../test/lang/objc/radar-9691614/main.m | 67 + .../test/lang/objc/rdar-10967107/Makefile | 7 + .../objc/rdar-10967107/TestRdar10967107.py | 73 + .../test/lang/objc/rdar-10967107/main.m | 13 + .../test/lang/objc/rdar-11355592/Makefile | 7 + .../objc/rdar-11355592/TestRdar11355592.py | 82 + .../test/lang/objc/rdar-11355592/main.m | 37 + .../test/lang/objc/rdar-12408181/Makefile | 11 + .../objc/rdar-12408181/TestRdar12408181.py | 64 + .../test/lang/objc/rdar-12408181/main.m | 24 + .../test/lang/objc/real-definition/Bar.h | 12 + .../test/lang/objc/real-definition/Bar.m | 43 + .../test/lang/objc/real-definition/Foo.h | 11 + .../test/lang/objc/real-definition/Foo.m | 25 + .../test/lang/objc/real-definition/Makefile | 6 + .../real-definition/TestRealDefinition.py | 101 + .../test/lang/objc/real-definition/main.m | 13 + .../lldbsuite/test/lang/objc/sample/Makefile | 6 + .../lldbsuite/test/lang/objc/sample/main.m | 70 + .../lldbsuite/test/lang/objc/self/Makefile | 6 + .../test/lang/objc/self/TestObjCSelf.py | 39 + .../lldbsuite/test/lang/objc/self/main.m | 54 + .../objc/single-entry-dictionary/Makefile | 7 + .../TestObjCSingleEntryDictionary.py | 78 + .../lang/objc/single-entry-dictionary/main.m | 7 + .../objc/unicode-string/TestUnicodeString.py | 6 + .../test/lang/objc/unicode-string/main.m | 5 + .../variadic_methods/TestVariadicMethods.py | 6 + .../test/lang/objc/variadic_methods/main.m | 31 + .../objcxx-ivar-vector/TestIvarVector.py | 6 + .../lang/objcxx/objcxx-ivar-vector/main.mm | 33 + .../test/lang/objcxx/sample/Makefile | 6 + .../lldbsuite/test/lang/objcxx/sample/main.mm | 71 + .../test/linux/builtin_trap/Makefile | 5 + .../linux/builtin_trap/TestBuiltinTrap.py | 53 + .../test/linux/builtin_trap/main.cpp | 17 + .../create_during_instruction_step/Makefile | 5 + .../TestCreateDuringInstructionStep.py | 85 + .../create_during_instruction_step/main.cpp | 55 + .../lldbsuite/test/lldb_pylint_helper.py | 181 + packages/Python/lldbsuite/test/lldbbench.py | 118 + packages/Python/lldbsuite/test/lldbcurses.py | 1308 ++ packages/Python/lldbsuite/test/lldbdwarf.py | 256 + packages/Python/lldbsuite/test/lldbinline.py | 251 + packages/Python/lldbsuite/test/lldbpexpect.py | 95 + .../Python/lldbsuite/test/lldbplatform.py | 45 + .../Python/lldbsuite/test/lldbplatformutil.py | 180 + packages/Python/lldbsuite/test/lldbtest.py | 2371 +++ .../Python/lldbsuite/test/lldbtest_config.py | 20 + packages/Python/lldbsuite/test/lldbutil.py | 1288 ++ packages/Python/lldbsuite/test/lock.py | 28 + .../Python/lldbsuite/test/logging/Makefile | 5 + .../lldbsuite/test/logging/TestLogging.py | 122 + .../Python/lldbsuite/test/logging/main.cpp | 62 + .../lldbsuite/test/macosx/add-dsym/Makefile | 11 + .../TestAddDsymMidExecutionCommand.py | 49 + .../lldbsuite/test/macosx/add-dsym/main.c | 7 + .../macosx/debug-info/apple_types/Makefile | 6 + .../apple_types/TestAppleTypesIsProduced.py | 71 + .../test/macosx/debug-info/apple_types/main.c | 27 + .../bundle-with-dot-in-filename/Makefile | 21 + .../TestBundleWithDotInFilename.py | 71 + .../bundle-with-dot-in-filename/bundle.c | 4 + .../bundle-with-dot-in-filename/main.c | 28 + .../macosx/find-dsym/deep-bundle/Info.plist | 44 + .../macosx/find-dsym/deep-bundle/Makefile | 28 + .../find-dsym/deep-bundle/MyFramework.h | 1 + .../find-dsym/deep-bundle/TestDeepBundle.py | 75 + .../test/macosx/find-dsym/deep-bundle/main.c | 22 + .../find-dsym/deep-bundle/myframework.c | 4 + .../test/macosx/indirect_symbol/Makefile | 48 + .../indirect_symbol/TestIndirectSymbols.py | 113 + .../test/macosx/indirect_symbol/alias.list | 1 + .../test/macosx/indirect_symbol/indirect.c | 14 + .../test/macosx/indirect_symbol/main.c | 14 + .../test/macosx/indirect_symbol/reexport.c | 7 + .../lldbsuite/test/macosx/nslog/Makefile | 6 + .../macosx/nslog/TestDarwinNSLogOutput.py | 151 + .../Python/lldbsuite/test/macosx/nslog/main.m | 18 + .../lldbsuite/test/macosx/order/Makefile | 7 + .../test/macosx/order/TestOrderFile.py | 39 + .../lldbsuite/test/macosx/order/cmds.txt | 3 + .../Python/lldbsuite/test/macosx/order/main.c | 54 + .../lldbsuite/test/macosx/order/order-file | 4 + .../lldbsuite/test/macosx/queues/Makefile | 28 + .../test/macosx/queues/TestQueues.py | 355 + .../lldbsuite/test/macosx/queues/main.c | 137 + .../test/macosx/safe-to-func-call/Makefile | 28 + .../safe-to-func-call/TestSafeFuncCalls.py | 73 + .../test/macosx/safe-to-func-call/main.c | 30 + .../test/macosx/thread-names/Makefile | 28 + .../thread-names/TestInterruptThreadNames.py | 132 + .../lldbsuite/test/macosx/thread-names/main.c | 36 + .../lldbsuite/test/macosx/universal/Makefile | 19 + .../test/macosx/universal/TestUniversal.py | 169 + .../lldbsuite/test/macosx/universal/main.c | 21 + .../Python/lldbsuite/test/make/Android.rules | 92 + .../Python/lldbsuite/test/make/Makefile.rules | 652 + .../lldbsuite/test/make/pseudo_barrier.h | 20 + .../Python/lldbsuite/test/make/test_common.h | 47 + .../lldbsuite/test/plugins/builder_base.py | 206 + .../lldbsuite/test/plugins/builder_darwin.py | 26 + .../lldbsuite/test/plugins/builder_freebsd.py | 10 + .../lldbsuite/test/plugins/builder_linux.py | 10 + .../lldbsuite/test/plugins/builder_netbsd.py | 10 + .../lldbsuite/test/plugins/builder_win32.py | 10 + .../lldbsuite/test/python_api/.categories | 1 + .../test/python_api/breakpoint/Makefile | 5 + .../breakpoint/TestBreakpointAPI.py | 77 + .../test/python_api/breakpoint/main.c | 14 + .../test/python_api/class_members/Makefile | 5 + .../class_members/TestSBTypeClassMembers.py | 107 + .../test/python_api/class_members/main.mm | 47 + .../python_api/debugger/TestDebuggerAPI.py | 43 + .../TestDefaultConstructorForAPIObjects.py | 399 + .../default-constructor/sb_address.py | 23 + .../default-constructor/sb_block.py | 18 + .../default-constructor/sb_breakpoint.py | 37 + .../sb_breakpointlocation.py | 29 + .../default-constructor/sb_broadcaster.py | 21 + .../default-constructor/sb_communication.py | 29 + .../default-constructor/sb_compileunit.py | 16 + .../default-constructor/sb_debugger.py | 57 + .../default-constructor/sb_error.py | 26 + .../default-constructor/sb_event.py | 18 + .../default-constructor/sb_filespec.py | 15 + .../default-constructor/sb_frame.py | 41 + .../default-constructor/sb_function.py | 20 + .../default-constructor/sb_instruction.py | 17 + .../default-constructor/sb_instructionlist.py | 18 + .../default-constructor/sb_lineentry.py | 15 + .../default-constructor/sb_listener.py | 24 + .../default-constructor/sb_module.py | 30 + .../default-constructor/sb_process.py | 50 + .../default-constructor/sb_section.py | 23 + .../default-constructor/sb_stringlist.py | 18 + .../default-constructor/sb_symbol.py | 17 + .../default-constructor/sb_symbolcontext.py | 16 + .../default-constructor/sb_target.py | 66 + .../default-constructor/sb_thread.py | 38 + .../python_api/default-constructor/sb_type.py | 23 + .../default-constructor/sb_value.py | 68 + .../default-constructor/sb_valuelist.py | 15 + .../default-constructor/sb_watchpoint.py | 22 + .../TestDisassembleRawData.py | 54 + .../TestDisassemble_VST1_64.py | 63 + .../lldbsuite/test/python_api/event/Makefile | 5 + .../test/python_api/event/TestEvents.py | 312 + .../lldbsuite/test/python_api/event/main.c | 49 + .../TestExprPathSynthetic.py | 6 + .../python_api/exprpath_synthetic/main.mm | 20 + .../python_api/findvalue_duplist/Makefile | 8 + .../findvalue_duplist/TestSBFrameFindValue.py | 84 + .../python_api/findvalue_duplist/main.cpp | 7 + .../test/python_api/formatters/Makefile | 8 + .../formatters/TestFormattersSBAPI.py | 496 + .../test/python_api/formatters/main.cpp | 59 + .../test/python_api/formatters/synth.py | 117 + .../lldbsuite/test/python_api/frame/Makefile | 5 + .../test/python_api/frame/TestFrames.py | 225 + .../python_api/frame/get-variables/Makefile | 5 + .../frame/get-variables/TestGetVariables.py | 296 + .../python_api/frame/get-variables/main.c | 29 + .../test/python_api/frame/inlines/Makefile | 9 + .../frame/inlines/TestInlinedFrame.py | 97 + .../test/python_api/frame/inlines/inlines.c | 53 + .../test/python_api/frame/inlines/inlines.h | 4 + .../lldbsuite/test/python_api/frame/main.c | 58 + .../test/python_api/function_symbol/Makefile | 5 + .../function_symbol/TestDisasmAPI.py | 125 + .../function_symbol/TestSymbolAPI.py | 94 + .../test/python_api/function_symbol/main.c | 60 + .../test/python_api/hello_world/Makefile | 7 + .../python_api/hello_world/TestHelloWorld.py | 151 + .../test/python_api/hello_world/main.c | 18 + .../test/python_api/interpreter/Makefile | 5 + .../interpreter/TestCommandInterpreterAPI.py | 75 + .../test/python_api/interpreter/main.c | 6 + .../test/python_api/lldbutil/frame/Makefile | 6 + .../lldbutil/frame/TestFrameUtils.py | 64 + .../test/python_api/lldbutil/frame/main.c | 47 + .../test/python_api/lldbutil/iter/Makefile | 8 + .../lldbutil/iter/TestLLDBIterator.py | 129 + .../lldbutil/iter/TestRegistersIterator.py | 107 + .../test/python_api/lldbutil/iter/main.cpp | 134 + .../test/python_api/lldbutil/process/Makefile | 8 + .../lldbutil/process/TestPrintStackTraces.py | 63 + .../test/python_api/lldbutil/process/main.cpp | 136 + .../test/python_api/module_section/Makefile | 8 + .../module_section/TestModuleAndSection.py | 143 + .../test/python_api/module_section/b.cpp | 3 + .../test/python_api/module_section/c.cpp | 3 + .../test/python_api/module_section/main.cpp | 136 + .../test/python_api/name_lookup/Makefile | 5 + .../python_api/name_lookup/TestNameLookup.py | 66 + .../test/python_api/name_lookup/main.cpp | 54 + .../test/python_api/objc_type/Makefile | 9 + .../test/python_api/objc_type/TestObjCType.py | 74 + .../test/python_api/objc_type/main.m | 52 + .../test/python_api/process/Makefile | 5 + .../test/python_api/process/TestProcessAPI.py | 327 + .../test/python_api/process/io/Makefile | 6 + .../python_api/process/io/TestProcessIO.py | 233 + .../test/python_api/process/io/main.c | 19 + .../test/python_api/process/main.cpp | 31 + .../test/python_api/rdar-12481949/Makefile | 5 + .../rdar-12481949/Test-rdar-12481949.py | 68 + .../test/python_api/rdar-12481949/main.cpp | 17 + .../lldbsuite/test/python_api/sbdata/Makefile | 5 + .../test/python_api/sbdata/TestSBData.py | 557 + .../lldbsuite/test/python_api/sbdata/main.cpp | 43 + .../sbstructureddata/TestStructuredDataAPI.py | 206 + .../sbtype_typeclass/TestSBTypeTypeClass.py | 10 + .../test/python_api/sbtype_typeclass/main.m | 34 + .../python_api/sbvalue_const_addrof/Makefile | 4 + .../TestSBValueConstAddrOf.py | 3 + .../python_api/sbvalue_const_addrof/main.cpp | 40 + .../test/python_api/sbvalue_persist/Makefile | 15 + .../sbvalue_persist/TestSBValuePersist.py | 85 + .../test/python_api/sbvalue_persist/main.cpp | 14 + .../test/python_api/section/Makefile | 5 + .../test/python_api/section/TestSectionAPI.py | 43 + .../lldbsuite/test/python_api/section/main.c | 28 + .../test/python_api/signals/Makefile | 5 + .../test/python_api/signals/TestSignalsAPI.py | 58 + .../test/python_api/signals/main.cpp | 28 + .../test/python_api/symbol-context/Makefile | 5 + .../symbol-context/TestSymbolContext.py | 108 + .../test/python_api/symbol-context/main.c | 51 + .../symbol-context/two-files/Makefile | 5 + .../two-files/TestSymbolContextTwoFiles.py | 83 + .../symbol-context/two-files/decls.h | 11 + .../symbol-context/two-files/file1.cpp | 21 + .../symbol-context/two-files/file2.cpp | 7 + .../lldbsuite/test/python_api/target/Makefile | 5 + .../test/python_api/target/TestTargetAPI.py | 413 + .../lldbsuite/test/python_api/target/main.c | 60 + .../lldbsuite/test/python_api/thread/Makefile | 5 + .../test/python_api/thread/TestThreadAPI.py | 277 + .../lldbsuite/test/python_api/thread/main.cpp | 26 + .../test/python_api/thread/main2.cpp | 54 + .../lldbsuite/test/python_api/type/Makefile | 5 + .../test/python_api/type/TestTypeList.py | 132 + .../lldbsuite/test/python_api/type/main.cpp | 60 + .../lldbsuite/test/python_api/value/Makefile | 5 + .../test/python_api/value/TestValueAPI.py | 168 + .../python_api/value/change_values/Makefile | 5 + .../value/change_values/TestChangeValueAPI.py | 185 + .../python_api/value/change_values/main.c | 29 + .../python_api/value/empty_class/Makefile | 5 + .../empty_class/TestValueAPIEmptyClass.py | 60 + .../python_api/value/empty_class/main.cpp | 16 + .../python_api/value/linked_list/Makefile | 5 + .../linked_list/TestValueAPILinkedList.py | 144 + .../python_api/value/linked_list/main.cpp | 56 + .../lldbsuite/test/python_api/value/main.c | 56 + .../test/python_api/value_var_update/Makefile | 8 + .../value_var_update/TestValueVarUpdate.py | 71 + .../test/python_api/value_var_update/main.c | 15 + .../test/python_api/watchpoint/Makefile | 5 + .../watchpoint/TestSetWatchpoint.py | 113 + .../watchpoint/TestWatchpointIgnoreCount.py | 99 + .../watchpoint/TestWatchpointIter.py | 127 + .../python_api/watchpoint/condition/Makefile | 5 + .../condition/TestWatchpointConditionAPI.py | 103 + .../python_api/watchpoint/condition/main.cpp | 28 + .../test/python_api/watchpoint/main.c | 24 + .../watchpoint/watchlocation/Makefile | 6 + .../watchlocation/TestSetWatchlocation.py | 107 + .../watchlocation/TestTargetWatchAddress.py | 155 + .../watchpoint/watchlocation/main.cpp | 104 + packages/Python/lldbsuite/test/redo.py | 203 + .../lldbsuite/test/sample_test/Makefile | 6 + .../test/sample_test/TestSampleInlineTest.py | 10 + .../test/sample_test/TestSampleTest.py | 50 + .../Python/lldbsuite/test/sample_test/main.c | 13 + .../Python/lldbsuite/test/settings/Makefile | 5 + .../lldbsuite/test/settings/TestSettings.py | 560 + .../Python/lldbsuite/test/settings/main.cpp | 75 + .../lldbsuite/test/settings/quoting/Makefile | 5 + .../test/settings/quoting/TestQuoting.py | 97 + .../lldbsuite/test/settings/quoting/main.c | 13 + .../lldbsuite/test/source-manager/Makefile | 5 + .../test/source-manager/TestSourceManager.py | 253 + .../test/source-manager/hidden/.keep | 0 .../lldbsuite/test/source-manager/main.c | 6 + .../test/terminal/TestSTTYBeforeAndAfter.py | 126 + .../Python/lldbsuite/test/test_categories.py | 87 + packages/Python/lldbsuite/test/test_result.py | 302 + .../lldbsuite/test/test_runner/README.txt | 5 + .../lldbsuite/test/test_runner/__init__.py | 0 .../test/test_runner/process_control.py | 739 + .../test/test_runner/test/__init__.py | 0 .../test/test_runner/test/inferior.py | 146 + .../test_runner/test/test_process_control.py | 243 + .../lldbsuite/test/tools/lldb-mi/Makefile | 5 + .../test/tools/lldb-mi/TestMiEnvironmentCd.py | 38 + .../test/tools/lldb-mi/TestMiExit.py | 94 + .../test/tools/lldb-mi/TestMiFile.py | 83 + .../test/tools/lldb-mi/TestMiGdbSetShow.py | 260 + .../test/tools/lldb-mi/TestMiLibraryLoaded.py | 59 + .../test/tools/lldb-mi/TestMiPrompt.py | 58 + .../test/tools/lldb-mi/breakpoint/Makefile | 5 + .../tools/lldb-mi/breakpoint/TestMiBreak.py | 358 + .../test/tools/lldb-mi/breakpoint/main.cpp | 30 + .../test/tools/lldb-mi/control/Makefile | 5 + .../test/tools/lldb-mi/control/TestMiExec.py | 503 + .../test/tools/lldb-mi/control/main.cpp | 33 + .../test/tools/lldb-mi/data/Makefile | 5 + .../test/tools/lldb-mi/data/TestMiData.py | 401 + .../test/tools/lldb-mi/data/main.cpp | 59 + .../test/tools/lldb-mi/interpreter/Makefile | 5 + .../lldb-mi/interpreter/TestMiCliSupport.py | 220 + .../interpreter/TestMiInterpreterExec.py | 247 + .../test/tools/lldb-mi/interpreter/main.cpp | 19 + .../test/tools/lldb-mi/lexical_scope/Makefile | 5 + .../lexical_scope/TestMiLexicalScope.py | 68 + .../test/tools/lldb-mi/lexical_scope/main.cpp | 33 + .../test/tools/lldb-mi/lldbmi_testcase.py | 54 + .../lldbsuite/test/tools/lldb-mi/main.cpp | 33 + .../test/tools/lldb-mi/signal/Makefile | 5 + .../test/tools/lldb-mi/signal/TestMiSignal.py | 225 + .../test/tools/lldb-mi/signal/main.cpp | 33 + .../test/tools/lldb-mi/stack/Makefile | 5 + .../test/tools/lldb-mi/stack/TestMiStack.py | 551 + .../test/tools/lldb-mi/stack/main.cpp | 142 + .../tools/lldb-mi/startup_options/Makefile | 5 + .../startup_options/TestMiStartupOptions.py | 302 + .../tools/lldb-mi/startup_options/main.cpp | 15 + .../lldb-mi/startup_options/start_script | 5 + .../startup_options/start_script_error | 2 + .../lldb-mi/startup_options/start_script_exit | 7 + .../test/tools/lldb-mi/symbol/Makefile | 5 + .../test/tools/lldb-mi/symbol/TestMiSymbol.py | 104 + .../test/tools/lldb-mi/symbol/main.cpp | 18 + .../symbol/symbol_list_lines_inline_test.cpp | 39 + .../symbol/symbol_list_lines_inline_test.h | 24 + .../symbol/symbol_list_lines_inline_test2.cpp | 38 + .../test/tools/lldb-mi/syntax/Makefile | 5 + .../test/tools/lldb-mi/syntax/TestMiSyntax.py | 193 + .../test/tools/lldb-mi/syntax/main.cpp | 17 + .../test/tools/lldb-mi/target/Makefile | 5 + .../test/tools/lldb-mi/target/TestMiTarget.py | 132 + .../test/tools/lldb-mi/target/test_attach.cpp | 21 + .../test/tools/lldb-mi/threadinfo/Makefile | 7 + .../lldb-mi/threadinfo/TestMiThreadInfo.py | 41 + .../lldb-mi/threadinfo/test_threadinfo.cpp | 21 + .../test/tools/lldb-mi/variable/Makefile | 5 + .../lldb-mi/variable/TestMiGdbSetShowPrint.py | 322 + .../test/tools/lldb-mi/variable/TestMiVar.py | 459 + .../test/tools/lldb-mi/variable/main.cpp | 152 + .../test/tools/lldb-server/.clang-format | 1 + .../lldbsuite/test/tools/lldb-server/Makefile | 8 + .../tools/lldb-server/TestGdbRemoteAttach.py | 66 + .../lldb-server/TestGdbRemoteAuxvSupport.py | 219 + .../TestGdbRemoteExpeditedRegisters.py | 159 + .../lldb-server/TestGdbRemoteHostInfo.py | 127 + .../tools/lldb-server/TestGdbRemoteKill.py | 58 + .../lldb-server/TestGdbRemoteModuleInfo.py | 43 + .../lldb-server/TestGdbRemoteProcessInfo.py | 206 + .../lldb-server/TestGdbRemoteRegisterState.py | 136 + .../lldb-server/TestGdbRemoteSingleStep.py | 40 + .../TestGdbRemoteThreadsInStopReply.py | 298 + .../TestGdbRemote_qThreadStopInfo.py | 180 + .../tools/lldb-server/TestGdbRemote_vCont.py | 147 + .../tools/lldb-server/TestLldbGdbServer.py | 1540 ++ .../commandline/TestStubReverseConnect.py | 97 + .../lldb-server/commandline/TestStubSetSID.py | 86 + .../test/tools/lldb-server/exit-code/Makefile | 8 + .../exit-code/TestGdbRemoteExitCode.py | 124 + .../test/tools/lldb-server/exit-code/main.cpp | 355 + .../tools/lldb-server/gdbremote_testcase.py | 1621 ++ .../tools/lldb-server/inferior-crash/Makefile | 8 + .../inferior-crash/TestGdbRemoteAbort.py | 45 + .../inferior-crash/TestGdbRemoteSegFault.py | 45 + .../tools/lldb-server/inferior-crash/main.cpp | 31 + .../tools/lldb-server/lldbgdbserverutils.py | 945 + .../lldbsuite/test/tools/lldb-server/main.cpp | 364 + .../platform-process-connect/Makefile | 5 + .../TestPlatformProcessConnect.py | 99 + .../platform-process-connect/main.cpp | 6 + .../lldb-server/signal-filtering/Makefile | 5 + .../TestGdbRemote_QPassSignals.py | 115 + .../lldb-server/signal-filtering/main.cpp | 37 + .../tools/lldb-server/socket_packet_pump.py | 197 + .../test/test_lldbgdbserverutils.py | 65 + .../tools/lldb-server/thread-name/Makefile | 6 + .../thread-name/TestGdbRemoteThreadName.py | 41 + .../tools/lldb-server/thread-name/main.cpp | 22 + .../lldbsuite/test/types/AbstractBase.py | 299 + .../lldbsuite/test/types/HideTestFailures.py | 80 + packages/Python/lldbsuite/test/types/Makefile | 7 + .../lldbsuite/test/types/TestFloatTypes.py | 45 + .../test/types/TestFloatTypesExpr.py | 49 + .../lldbsuite/test/types/TestIntegerTypes.py | 123 + .../test/types/TestIntegerTypesExpr.py | 125 + .../test/types/TestRecursiveTypes.py | 59 + .../lldbsuite/test/types/basic_type.cpp | 211 + packages/Python/lldbsuite/test/types/char.cpp | 9 + .../Python/lldbsuite/test/types/double.cpp | 9 + .../Python/lldbsuite/test/types/float.cpp | 9 + packages/Python/lldbsuite/test/types/int.cpp | 9 + packages/Python/lldbsuite/test/types/long.cpp | 18 + .../Python/lldbsuite/test/types/long_long.cpp | 18 + .../lldbsuite/test/types/recursive_type_1.cpp | 12 + .../lldbsuite/test/types/recursive_type_2.cpp | 10 + .../test/types/recursive_type_main.cpp | 8 + .../Python/lldbsuite/test/types/short.cpp | 9 + .../lldbsuite/test/types/unsigned_char.cpp | 9 + .../lldbsuite/test/types/unsigned_int.cpp | 9 + .../lldbsuite/test/types/unsigned_long.cpp | 18 + .../test/types/unsigned_long_long.cpp | 18 + .../lldbsuite/test/types/unsigned_short.cpp | 9 + .../lldbsuite/test/warnings/uuid/Makefile | 5 + .../test/warnings/uuid/TestAddDsymCommand.py | 125 + .../test/warnings/uuid/main.cpp.template | 19 + .../Python/lldbsuite/test_event/__init__.py | 0 .../lldbsuite/test_event/build_exception.py | 16 + .../lldbsuite/test_event/dotest_channels.py | 209 + .../lldbsuite/test_event/event_builder.py | 482 + .../test_event/formatter/__init__.py | 163 + .../lldbsuite/test_event/formatter/curses.py | 342 + .../test_event/formatter/dump_formatter.py | 23 + .../lldbsuite/test_event/formatter/pickled.py | 80 + .../test_event/formatter/results_formatter.py | 766 + .../lldbsuite/test_event/formatter/xunit.py | 594 + .../invalid_decorator/TestInvalidDecorator.py | 13 + .../test/src/TestCatchInvalidDecorator.py | 70 + .../test_event/test/src/event_collector.py | 85 + resources/LLDB-Info.plist | 24 + scripts/CMakeLists.txt | 60 + scripts/Python/android/host_art_bt.py | 237 + scripts/Python/finish-swig-Python-LLDB.sh | 310 + scripts/Python/finishSwigPythonLLDB.py | 945 + scripts/Python/modify-python-lldb.py | 500 + scripts/Python/modules/CMakeLists.txt | 11 + .../Python/modules/readline/CMakeLists.txt | 25 + scripts/Python/modules/readline/readline.cpp | 87 + scripts/Python/prepare_binding_Python.py | 441 + scripts/Python/python-extensions.swig | 1153 ++ scripts/Python/python-swigsafecast.swig | 142 + scripts/Python/python-typemaps.swig | 590 + scripts/Python/python-wrapper.swig | 937 + scripts/Python/remote-build.py | 312 + scripts/Python/use_lldb_suite.py | 26 + scripts/Xcode/build-llvm.py | 440 + scripts/Xcode/lldbbuild.py | 188 + scripts/Xcode/package-clang-headers.py | 82 + scripts/Xcode/prepare-gtest-run-dir.sh | 10 + scripts/Xcode/repo.py | 54 + scripts/Xcode/repos/FALLBACK | 19 + scripts/Xcode/repos/svn-trunk.json | 19 + scripts/analyze-project-deps.py | 208 + scripts/build-lldb-llvm-clang | 74 + scripts/buildbot.py | 196 + scripts/checkpoint-llvm.pl | 126 + scripts/disasm-gdb-remote.pl | 2283 +++ scripts/finish-swig-wrapper-classes.sh | 101 + scripts/finishSwigWrapperClasses.py | 410 + scripts/generate-vers.pl | 56 + scripts/get_relative_lib_dir.py | 44 + scripts/install-lldb.sh | 59 + scripts/install_custom_python.py | 175 + scripts/interface/SBAddress.i | 201 + scripts/interface/SBAttachInfo.i | 116 + scripts/interface/SBBlock.i | 179 + scripts/interface/SBBreakpoint.i | 301 + scripts/interface/SBBreakpointLocation.i | 130 + scripts/interface/SBBroadcaster.i | 68 + scripts/interface/SBCommandInterpreter.i | 218 + scripts/interface/SBCommandReturnObject.i | 113 + scripts/interface/SBCommunication.i | 82 + scripts/interface/SBCompileUnit.i | 130 + scripts/interface/SBData.i | 340 + scripts/interface/SBDebugger.i | 398 + scripts/interface/SBDeclaration.i | 68 + scripts/interface/SBError.i | 128 + scripts/interface/SBEvent.i | 153 + scripts/interface/SBExecutionContext.i | 57 + scripts/interface/SBExpressionOptions.i | 151 + scripts/interface/SBFileSpec.i | 106 + scripts/interface/SBFileSpecList.i | 45 + scripts/interface/SBFrame.i | 415 + scripts/interface/SBFunction.i | 145 + scripts/interface/SBHostOS.i | 50 + scripts/interface/SBInstruction.i | 109 + scripts/interface/SBInstructionList.i | 94 + scripts/interface/SBLanguageRuntime.i | 22 + scripts/interface/SBLaunchInfo.i | 132 + scripts/interface/SBLineEntry.i | 106 + scripts/interface/SBListener.i | 99 + scripts/interface/SBMemoryRegionInfo.i | 58 + scripts/interface/SBMemoryRegionInfoList.i | 38 + scripts/interface/SBModule.i | 530 + scripts/interface/SBModuleSpec.i | 133 + scripts/interface/SBPlatform.i | 196 + scripts/interface/SBProcess.i | 518 + scripts/interface/SBQueue.i | 75 + scripts/interface/SBQueueItem.i | 46 + scripts/interface/SBSection.i | 157 + scripts/interface/SBSourceManager.i | 61 + scripts/interface/SBStream.i | 100 + scripts/interface/SBStringList.i | 44 + scripts/interface/SBStructuredData.i | 62 + scripts/interface/SBSymbol.i | 110 + scripts/interface/SBSymbolContext.i | 112 + scripts/interface/SBSymbolContextList.i | 140 + scripts/interface/SBTarget.i | 1036 ++ scripts/interface/SBThread.i | 450 + scripts/interface/SBThreadCollection.i | 38 + scripts/interface/SBThreadPlan.i | 126 + scripts/interface/SBTrace.i | 34 + scripts/interface/SBTraceOptions.i | 38 + scripts/interface/SBType.i | 503 + scripts/interface/SBTypeCategory.i | 246 + scripts/interface/SBTypeEnumMember.i | 108 + scripts/interface/SBTypeFilter.i | 75 + scripts/interface/SBTypeFormat.i | 78 + scripts/interface/SBTypeNameSpecifier.i | 68 + scripts/interface/SBTypeSummary.i | 123 + scripts/interface/SBTypeSynthetic.i | 80 + scripts/interface/SBUnixSignals.i | 74 + scripts/interface/SBValue.i | 563 + scripts/interface/SBValueList.i | 142 + scripts/interface/SBVariablesOptions.i | 61 + scripts/interface/SBWatchpoint.i | 99 + scripts/lldb.swig | 231 + scripts/prepare_bindings.py | 218 + scripts/sed-sources | 251 + scripts/shush | 64 + scripts/swig_bot.py | 85 + scripts/swig_bot_lib/__init__.py | 0 scripts/swig_bot_lib/client.py | 216 + scripts/swig_bot_lib/local.py | 135 + scripts/swig_bot_lib/remote.py | 43 + scripts/swig_bot_lib/server.py | 144 + scripts/use_lldb_suite.py | 26 + scripts/utilsArgsParse.py | 141 + scripts/utilsDebug.py | 125 + scripts/utilsOsType.py | 99 + scripts/verify_api.py | 115 + source/API/CMakeLists.txt | 174 + source/API/SBAddress.cpp | 250 + source/API/SBAttachInfo.cpp | 167 + source/API/SBBlock.cpp | 297 + source/API/SBBreakpoint.cpp | 816 + source/API/SBBreakpointLocation.cpp | 326 + source/API/SBBroadcaster.cpp | 151 + source/API/SBCommandInterpreter.cpp | 616 + source/API/SBCommandReturnObject.cpp | 281 + source/API/SBCommunication.cpp | 255 + source/API/SBCompileUnit.cpp | 223 + source/API/SBData.cpp | 704 + source/API/SBDebugger.cpp | 1149 ++ source/API/SBDeclaration.cpp | 153 + source/API/SBError.cpp | 173 + source/API/SBEvent.cpp | 187 + source/API/SBExecutionContext.cpp | 102 + source/API/SBExpressionOptions.cpp | 168 + source/API/SBFileSpec.cpp | 167 + source/API/SBFileSpecList.cpp | 103 + source/API/SBFrame.cpp | 1490 ++ source/API/SBFunction.cpp | 222 + source/API/SBHostOS.cpp | 116 + source/API/SBInstruction.cpp | 285 + source/API/SBInstructionList.cpp | 137 + source/API/SBLanguageRuntime.cpp | 25 + source/API/SBLaunchInfo.cpp | 190 + source/API/SBLineEntry.cpp | 190 + source/API/SBListener.cpp | 314 + source/API/SBMemoryRegionInfo.cpp | 98 + source/API/SBMemoryRegionInfoList.cpp | 117 + source/API/SBModule.cpp | 567 + source/API/SBModuleSpec.cpp | 157 + source/API/SBPlatform.cpp | 484 + source/API/SBProcess.cpp | 1371 ++ source/API/SBQueue.cpp | 347 + source/API/SBQueueItem.cpp | 134 + source/API/SBSection.cpp | 236 + source/API/SBSourceManager.cpp | 116 + source/API/SBStream.cpp | 154 + source/API/SBStringList.cpp | 109 + source/API/SBStructuredData.cpp | 111 + source/API/SBSymbol.cpp | 177 + source/API/SBSymbolContext.cpp | 216 + source/API/SBSymbolContextList.cpp | 81 + source/API/SBTarget.cpp | 2192 +++ source/API/SBThread.cpp | 1440 ++ source/API/SBThreadCollection.cpp | 67 + source/API/SBThreadPlan.cpp | 210 + source/API/SBTrace.cpp | 109 + source/API/SBTraceOptions.cpp | 94 + source/API/SBType.cpp | 669 + source/API/SBTypeCategory.cpp | 565 + source/API/SBTypeEnumMember.cpp | 141 + source/API/SBTypeFilter.cpp | 145 + source/API/SBTypeFormat.cpp | 148 + source/API/SBTypeNameSpecifier.cpp | 117 + source/API/SBTypeSummary.cpp | 378 + source/API/SBTypeSynthetic.cpp | 164 + source/API/SBUnixSignals.cpp | 143 + source/API/SBValue.cpp | 1607 ++ source/API/SBValueList.cpp | 209 + source/API/SBVariablesOptions.cpp | 155 + source/API/SBWatchpoint.cpp | 247 + source/API/SystemInitializerFull.cpp | 512 + source/API/liblldb-private.exports | 6 + source/API/liblldb.exports | 4 + source/API/liblldb.xcode.exports | 3 + source/Breakpoint/Breakpoint.cpp | 1110 ++ source/Breakpoint/BreakpointID.cpp | 118 + source/Breakpoint/BreakpointIDList.cpp | 339 + source/Breakpoint/BreakpointList.cpp | 218 + source/Breakpoint/BreakpointLocation.cpp | 636 + .../BreakpointLocationCollection.cpp | 185 + source/Breakpoint/BreakpointLocationList.cpp | 310 + source/Breakpoint/BreakpointOptions.cpp | 564 + source/Breakpoint/BreakpointResolver.cpp | 323 + .../Breakpoint/BreakpointResolverAddress.cpp | 195 + .../Breakpoint/BreakpointResolverFileLine.cpp | 237 + .../BreakpointResolverFileRegex.cpp | 180 + source/Breakpoint/BreakpointResolverName.cpp | 424 + source/Breakpoint/BreakpointSite.cpp | 203 + source/Breakpoint/BreakpointSiteList.cpp | 206 + source/Breakpoint/CMakeLists.txt | 36 + source/Breakpoint/Stoppoint.cpp | 33 + .../Breakpoint/StoppointCallbackContext.cpp | 29 + source/Breakpoint/StoppointLocation.cpp | 41 + source/Breakpoint/Watchpoint.cpp | 388 + source/Breakpoint/WatchpointList.cpp | 257 + source/Breakpoint/WatchpointOptions.cpp | 199 + source/CMakeLists.txt | 88 + source/Commands/CMakeLists.txt | 48 + source/Commands/CommandCompletions.cpp | 569 + source/Commands/CommandObjectApropos.cpp | 112 + source/Commands/CommandObjectApropos.h | 38 + source/Commands/CommandObjectArgs.cpp | 234 + source/Commands/CommandObjectArgs.h | 52 + source/Commands/CommandObjectBreakpoint.cpp | 2441 +++ source/Commands/CommandObjectBreakpoint.h | 58 + .../CommandObjectBreakpointCommand.cpp | 753 + .../Commands/CommandObjectBreakpointCommand.h | 40 + source/Commands/CommandObjectBugreport.cpp | 131 + source/Commands/CommandObjectBugreport.h | 34 + source/Commands/CommandObjectCommands.cpp | 1962 +++ source/Commands/CommandObjectCommands.h | 37 + source/Commands/CommandObjectDisassemble.cpp | 563 + source/Commands/CommandObjectDisassemble.h | 89 + source/Commands/CommandObjectExpression.cpp | 640 + source/Commands/CommandObjectExpression.h | 95 + source/Commands/CommandObjectFrame.cpp | 758 + source/Commands/CommandObjectFrame.h | 36 + source/Commands/CommandObjectGUI.cpp | 58 + source/Commands/CommandObjectGUI.h | 37 + source/Commands/CommandObjectHelp.cpp | 243 + source/Commands/CommandObjectHelp.h | 99 + source/Commands/CommandObjectLanguage.cpp | 31 + source/Commands/CommandObjectLanguage.h | 34 + source/Commands/CommandObjectLog.cpp | 379 + source/Commands/CommandObjectLog.h | 46 + source/Commands/CommandObjectMemory.cpp | 1792 ++ source/Commands/CommandObjectMemory.h | 30 + source/Commands/CommandObjectMultiword.cpp | 418 + source/Commands/CommandObjectPlatform.cpp | 1912 ++ source/Commands/CommandObjectPlatform.h | 38 + source/Commands/CommandObjectPlugin.cpp | 94 + source/Commands/CommandObjectPlugin.h | 33 + source/Commands/CommandObjectProcess.cpp | 1658 ++ source/Commands/CommandObjectProcess.h | 34 + source/Commands/CommandObjectQuit.cpp | 86 + source/Commands/CommandObjectQuit.h | 39 + source/Commands/CommandObjectRegister.cpp | 410 + source/Commands/CommandObjectRegister.h | 43 + source/Commands/CommandObjectSettings.cpp | 1052 ++ source/Commands/CommandObjectSettings.h | 36 + source/Commands/CommandObjectSource.cpp | 1330 ++ source/Commands/CommandObjectSource.h | 37 + source/Commands/CommandObjectSyntax.cpp | 103 + source/Commands/CommandObjectSyntax.h | 37 + source/Commands/CommandObjectTarget.cpp | 4913 ++++++ source/Commands/CommandObjectTarget.h | 36 + source/Commands/CommandObjectThread.cpp | 2097 +++ source/Commands/CommandObjectThread.h | 30 + source/Commands/CommandObjectType.cpp | 3226 ++++ source/Commands/CommandObjectType.h | 34 + source/Commands/CommandObjectVersion.cpp | 42 + source/Commands/CommandObjectVersion.h | 37 + source/Commands/CommandObjectWatchpoint.cpp | 1234 ++ source/Commands/CommandObjectWatchpoint.h | 40 + .../CommandObjectWatchpointCommand.cpp | 690 + .../Commands/CommandObjectWatchpointCommand.h | 38 + source/Core/Address.cpp | 1013 ++ source/Core/AddressRange.cpp | 195 + source/Core/AddressResolver.cpp | 46 + source/Core/AddressResolverFileLine.cpp | 88 + source/Core/AddressResolverName.cpp | 201 + source/Core/ArchSpec.cpp | 1672 ++ source/Core/Broadcaster.cpp | 480 + source/Core/CMakeLists.txt | 84 + source/Core/Communication.cpp | 423 + source/Core/Debugger.cpp | 1776 ++ source/Core/Disassembler.cpp | 1463 ++ source/Core/DumpDataExtractor.cpp | 825 + source/Core/DynamicLoader.cpp | 249 + source/Core/EmulateInstruction.cpp | 592 + source/Core/Event.cpp | 303 + source/Core/FileLineResolver.cpp | 93 + source/Core/FileSpecList.cpp | 182 + source/Core/FormatEntity.cpp | 2418 +++ source/Core/IOHandler.cpp | 4688 +++++ source/Core/Listener.cpp | 472 + source/Core/Mangled.cpp | 461 + source/Core/Module.cpp | 1728 ++ source/Core/ModuleChild.cpp | 32 + source/Core/ModuleList.cpp | 995 ++ source/Core/Opcode.cpp | 140 + source/Core/PluginManager.cpp | 2563 +++ source/Core/RegisterValue.cpp | 965 + source/Core/Scalar.cpp | 3069 ++++ source/Core/SearchFilter.cpp | 852 + source/Core/Section.cpp | 611 + source/Core/SourceManager.cpp | 716 + source/Core/State.cpp | 115 + source/Core/StreamAsynchronousIO.cpp | 37 + source/Core/StreamFile.cpp | 47 + source/Core/UserSettingsController.cpp | 114 + source/Core/Value.cpp | 715 + source/Core/ValueObject.cpp | 3447 ++++ source/Core/ValueObjectCast.cpp | 93 + source/Core/ValueObjectChild.cpp | 231 + source/Core/ValueObjectConstResult.cpp | 295 + source/Core/ValueObjectConstResultCast.cpp | 63 + source/Core/ValueObjectConstResultChild.cpp | 70 + source/Core/ValueObjectConstResultImpl.cpp | 175 + source/Core/ValueObjectDynamicValue.cpp | 396 + source/Core/ValueObjectList.cpp | 118 + source/Core/ValueObjectMemory.cpp | 230 + source/Core/ValueObjectRegister.cpp | 358 + source/Core/ValueObjectSyntheticFilter.cpp | 386 + source/Core/ValueObjectVariable.cpp | 403 + source/DataFormatters/CMakeLists.txt | 29 + source/DataFormatters/CXXFunctionPointer.cpp | 57 + source/DataFormatters/DataVisualization.cpp | 226 + .../DataFormatters/DumpValueObjectOptions.cpp | 206 + source/DataFormatters/FormatCache.cpp | 224 + source/DataFormatters/FormatClasses.cpp | 54 + source/DataFormatters/FormatManager.cpp | 1069 ++ source/DataFormatters/FormattersHelpers.cpp | 152 + source/DataFormatters/LanguageCategory.cpp | 232 + source/DataFormatters/StringPrinter.cpp | 652 + source/DataFormatters/TypeCategory.cpp | 628 + source/DataFormatters/TypeCategoryMap.cpp | 382 + source/DataFormatters/TypeFormat.cpp | 209 + source/DataFormatters/TypeSummary.cpp | 216 + source/DataFormatters/TypeSynthetic.cpp | 227 + source/DataFormatters/TypeValidator.cpp | 58 + source/DataFormatters/ValueObjectPrinter.cpp | 838 + source/DataFormatters/VectorType.cpp | 299 + source/Expression/CMakeLists.txt | 38 + source/Expression/DWARFExpression.cpp | 3394 ++++ source/Expression/DiagnosticManager.cpp | 90 + source/Expression/Expression.cpp | 29 + source/Expression/ExpressionSourceCode.cpp | 384 + source/Expression/ExpressionVariable.cpp | 82 + source/Expression/FunctionCaller.cpp | 394 + source/Expression/IRDynamicChecks.cpp | 612 + source/Expression/IRExecutionUnit.cpp | 1269 ++ source/Expression/IRInterpreter.cpp | 1705 ++ source/Expression/IRMemoryMap.cpp | 845 + source/Expression/LLVMUserExpression.cpp | 379 + source/Expression/Materializer.cpp | 1447 ++ source/Expression/REPL.cpp | 585 + source/Expression/UserExpression.cpp | 388 + source/Expression/UtilityFunction.cpp | 115 + source/Host/CMakeLists.txt | 191 + source/Host/android/HostInfoAndroid.cpp | 93 + source/Host/android/LibcGlue.cpp | 29 + source/Host/common/Editline.cpp | 1397 ++ source/Host/common/File.cpp | 842 + source/Host/common/FileCache.cpp | 113 + source/Host/common/FileSystem.cpp | 28 + source/Host/common/GetOptInc.cpp | 452 + source/Host/common/Host.cpp | 684 + source/Host/common/HostInfoBase.cpp | 361 + source/Host/common/HostNativeThreadBase.cpp | 67 + source/Host/common/HostProcess.cpp | 48 + source/Host/common/HostThread.cpp | 47 + source/Host/common/LockFileBase.cpp | 82 + source/Host/common/MainLoop.cpp | 387 + .../Host/common/MonitoringProcessLauncher.cpp | 97 + source/Host/common/NativeBreakpoint.cpp | 109 + source/Host/common/NativeBreakpointList.cpp | 229 + source/Host/common/NativeProcessProtocol.cpp | 493 + source/Host/common/NativeRegisterContext.cpp | 439 + source/Host/common/NativeThreadProtocol.cpp | 64 + source/Host/common/NativeWatchpointList.cpp | 31 + source/Host/common/OptionParser.cpp | 82 + source/Host/common/PipeBase.cpp | 25 + source/Host/common/ProcessRunLock.cpp | 71 + source/Host/common/PseudoTerminal.cpp | 310 + source/Host/common/Socket.cpp | 465 + source/Host/common/SocketAddress.cpp | 345 + source/Host/common/SoftwareBreakpoint.cpp | 353 + source/Host/common/StringConvert.cpp | 100 + source/Host/common/Symbols.cpp | 316 + source/Host/common/TCPSocket.cpp | 302 + source/Host/common/Terminal.cpp | 263 + source/Host/common/ThreadLauncher.cpp | 85 + source/Host/common/UDPSocket.cpp | 137 + source/Host/common/XML.cpp | 531 + source/Host/freebsd/Host.cpp | 250 + source/Host/freebsd/HostInfoFreeBSD.cpp | 76 + source/Host/linux/AbstractSocket.cpp | 22 + source/Host/linux/Host.cpp | 311 + source/Host/linux/HostInfoLinux.cpp | 244 + source/Host/linux/LibcGlue.cpp | 31 + source/Host/linux/ProcessLauncherLinux.cpp | 0 source/Host/linux/Support.cpp | 44 + source/Host/macosx/Host.mm | 1742 ++ source/Host/macosx/HostInfoMacOSX.mm | 337 + source/Host/macosx/HostThreadMacOSX.mm | 70 + source/Host/macosx/Symbols.cpp | 604 + source/Host/macosx/cfcpp/CFCBundle.cpp | 83 + source/Host/macosx/cfcpp/CFCBundle.h | 42 + source/Host/macosx/cfcpp/CFCData.cpp | 66 + source/Host/macosx/cfcpp/CFCData.h | 35 + source/Host/macosx/cfcpp/CFCMutableArray.cpp | 140 + source/Host/macosx/cfcpp/CFCMutableArray.h | 46 + .../macosx/cfcpp/CFCMutableDictionary.cpp | 469 + .../Host/macosx/cfcpp/CFCMutableDictionary.h | 75 + source/Host/macosx/cfcpp/CFCMutableSet.cpp | 89 + source/Host/macosx/cfcpp/CFCMutableSet.h | 47 + source/Host/macosx/cfcpp/CFCReleaser.h | 128 + source/Host/macosx/cfcpp/CFCString.cpp | 161 + source/Host/macosx/cfcpp/CFCString.h | 41 + source/Host/macosx/cfcpp/CoreFoundationCPP.h | 30 + source/Host/netbsd/Host.cpp | 256 + source/Host/netbsd/HostInfoNetBSD.cpp | 96 + source/Host/openbsd/Host.cpp | 222 + source/Host/openbsd/HostInfoOpenBSD.cpp | 65 + .../posix/ConnectionFileDescriptorPosix.cpp | 785 + source/Host/posix/DomainSocket.cpp | 127 + source/Host/posix/FileSystem.cpp | 80 + source/Host/posix/HostInfoPosix.cpp | 232 + source/Host/posix/HostProcessPosix.cpp | 95 + source/Host/posix/HostThreadPosix.cpp | 65 + source/Host/posix/LockFilePosix.cpp | 61 + source/Host/posix/PipePosix.cpp | 318 + .../Host/posix/ProcessLauncherPosixFork.cpp | 234 + .../windows/ConnectionGenericFileWindows.cpp | 331 + source/Host/windows/EditLineWin.cpp | 350 + source/Host/windows/FileSystem.cpp | 98 + source/Host/windows/Host.cpp | 281 + source/Host/windows/HostInfoWindows.cpp | 133 + source/Host/windows/HostProcessWindows.cpp | 120 + source/Host/windows/HostThreadWindows.cpp | 71 + source/Host/windows/LockFileWindows.cpp | 79 + source/Host/windows/PipeWindows.cpp | 297 + .../Host/windows/ProcessLauncherWindows.cpp | 149 + source/Host/windows/ProcessRunLock.cpp | 82 + source/Host/windows/Windows.cpp | 231 + source/Initialization/CMakeLists.txt | 33 + source/Initialization/SystemInitializer.cpp | 16 + .../SystemInitializerCommon.cpp | 127 + .../Initialization/SystemLifetimeManager.cpp | 53 + source/Interpreter/Args.cpp | 1495 ++ source/Interpreter/CMakeLists.txt | 57 + source/Interpreter/CommandAlias.cpp | 252 + source/Interpreter/CommandHistory.cpp | 110 + source/Interpreter/CommandInterpreter.cpp | 3078 ++++ source/Interpreter/CommandObject.cpp | 1126 ++ .../Interpreter/CommandObjectRegexCommand.cpp | 121 + source/Interpreter/CommandObjectScript.cpp | 86 + source/Interpreter/CommandObjectScript.h | 38 + .../Interpreter/CommandOptionValidators.cpp | 37 + source/Interpreter/CommandReturnObject.cpp | 175 + .../Interpreter/OptionGroupArchitecture.cpp | 67 + source/Interpreter/OptionGroupBoolean.cpp | 61 + source/Interpreter/OptionGroupFile.cpp | 83 + source/Interpreter/OptionGroupFormat.cpp | 277 + source/Interpreter/OptionGroupOutputFile.cpp | 69 + source/Interpreter/OptionGroupPlatform.cpp | 160 + source/Interpreter/OptionGroupString.cpp | 52 + source/Interpreter/OptionGroupUInt64.cpp | 52 + source/Interpreter/OptionGroupUUID.cpp | 58 + .../OptionGroupValueObjectDisplay.cpp | 228 + source/Interpreter/OptionGroupVariable.cpp | 143 + source/Interpreter/OptionGroupWatchpoint.cpp | 99 + source/Interpreter/OptionValue.cpp | 626 + source/Interpreter/OptionValueArch.cpp | 86 + source/Interpreter/OptionValueArgs.cpp | 30 + source/Interpreter/OptionValueArray.cpp | 311 + source/Interpreter/OptionValueBoolean.cpp | 98 + source/Interpreter/OptionValueChar.cpp | 68 + source/Interpreter/OptionValueDictionary.cpp | 324 + source/Interpreter/OptionValueEnumeration.cpp | 131 + source/Interpreter/OptionValueFileSpec.cpp | 127 + .../Interpreter/OptionValueFileSpecLIst.cpp | 164 + source/Interpreter/OptionValueFormat.cpp | 67 + .../Interpreter/OptionValueFormatEntity.cpp | 115 + source/Interpreter/OptionValueLanguage.cpp | 81 + .../Interpreter/OptionValuePathMappings.cpp | 208 + source/Interpreter/OptionValueProperties.cpp | 677 + source/Interpreter/OptionValueRegex.cpp | 72 + source/Interpreter/OptionValueSInt64.cpp | 80 + source/Interpreter/OptionValueString.cpp | 153 + source/Interpreter/OptionValueUInt64.cpp | 80 + source/Interpreter/OptionValueUUID.cpp | 107 + source/Interpreter/Options.cpp | 953 + source/Interpreter/Property.cpp | 299 + source/Interpreter/ScriptInterpreter.cpp | 102 + source/Interpreter/embedded_interpreter.py | 133 + source/Plugins/ABI/CMakeLists.txt | 13 + .../Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp | 2060 +++ source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h | 102 + source/Plugins/ABI/MacOSX-arm/CMakeLists.txt | 11 + .../ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp | 2453 +++ .../ABI/MacOSX-arm64/ABIMacOSX_arm64.h | 110 + .../Plugins/ABI/MacOSX-arm64/CMakeLists.txt | 10 + .../ABI/MacOSX-i386/ABIMacOSX_i386.cpp | 1143 ++ .../Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h | 109 + source/Plugins/ABI/MacOSX-i386/CMakeLists.txt | 10 + source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp | 2165 +++ source/Plugins/ABI/SysV-arm/ABISysV_arm.h | 102 + source/Plugins/ABI/SysV-arm/CMakeLists.txt | 11 + .../Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp | 2422 +++ source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h | 109 + source/Plugins/ABI/SysV-arm64/CMakeLists.txt | 10 + .../ABI/SysV-hexagon/ABISysV_hexagon.cpp | 1365 ++ .../ABI/SysV-hexagon/ABISysV_hexagon.h | 114 + .../Plugins/ABI/SysV-hexagon/CMakeLists.txt | 10 + source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp | 859 + source/Plugins/ABI/SysV-i386/ABISysV_i386.h | 117 + source/Plugins/ABI/SysV-i386/CMakeLists.txt | 10 + source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp | 1079 ++ source/Plugins/ABI/SysV-mips/ABISysV_mips.h | 104 + source/Plugins/ABI/SysV-mips/CMakeLists.txt | 10 + .../ABI/SysV-mips64/ABISysV_mips64.cpp | 1228 ++ .../Plugins/ABI/SysV-mips64/ABISysV_mips64.h | 117 + source/Plugins/ABI/SysV-mips64/CMakeLists.txt | 10 + source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp | 1023 ++ source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h | 113 + source/Plugins/ABI/SysV-ppc/CMakeLists.txt | 10 + .../Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp | 1027 ++ source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h | 113 + source/Plugins/ABI/SysV-ppc64/CMakeLists.txt | 10 + .../Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp | 753 + source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h | 107 + source/Plugins/ABI/SysV-s390x/CMakeLists.txt | 10 + .../ABI/SysV-x86_64/ABISysV_x86_64.cpp | 1981 +++ .../Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h | 115 + source/Plugins/ABI/SysV-x86_64/CMakeLists.txt | 10 + source/Plugins/CMakeLists.txt | 21 + source/Plugins/Disassembler/CMakeLists.txt | 1 + .../Plugins/Disassembler/llvm/CMakeLists.txt | 14 + .../Disassembler/llvm/DisassemblerLLVMC.cpp | 1375 ++ .../Disassembler/llvm/DisassemblerLLVMC.h | 152 + source/Plugins/DynamicLoader/CMakeLists.txt | 9 + .../Darwin-Kernel/CMakeLists.txt | 13 + .../DynamicLoaderDarwinKernel.cpp | 1586 ++ .../Darwin-Kernel/DynamicLoaderDarwinKernel.h | 305 + .../DynamicLoader/Hexagon-DYLD/CMakeLists.txt | 10 + .../Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp | 620 + .../Hexagon-DYLD/DynamicLoaderHexagonDYLD.h | 147 + .../Hexagon-DYLD/HexagonDYLDRendezvous.cpp | 372 + .../Hexagon-DYLD/HexagonDYLDRendezvous.h | 247 + .../DynamicLoader/MacOSX-DYLD/CMakeLists.txt | 16 + .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 1173 ++ .../MacOSX-DYLD/DynamicLoaderDarwin.h | 245 + .../MacOSX-DYLD/DynamicLoaderMacOS.cpp | 529 + .../MacOSX-DYLD/DynamicLoaderMacOS.h | 117 + .../MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp | 1228 ++ .../MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h | 186 + .../DynamicLoader/POSIX-DYLD/AuxVector.cpp | 142 + .../DynamicLoader/POSIX-DYLD/AuxVector.h | 111 + .../DynamicLoader/POSIX-DYLD/CMakeLists.txt | 15 + .../POSIX-DYLD/DYLDRendezvous.cpp | 612 + .../DynamicLoader/POSIX-DYLD/DYLDRendezvous.h | 256 + .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp | 720 + .../POSIX-DYLD/DynamicLoaderPOSIXDYLD.h | 164 + .../DynamicLoader/Static/CMakeLists.txt | 10 + .../Static/DynamicLoaderStatic.cpp | 167 + .../Static/DynamicLoaderStatic.h | 70 + .../DynamicLoader/Windows-DYLD/CMakeLists.txt | 9 + .../Windows-DYLD/DynamicLoaderWindowsDYLD.cpp | 76 + .../Windows-DYLD/DynamicLoaderWindowsDYLD.h | 47 + .../Plugins/ExpressionParser/CMakeLists.txt | 2 + .../ExpressionParser/Clang/ASTDumper.cpp | 109 + .../ExpressionParser/Clang/ASTDumper.h | 41 + .../Clang/ASTResultSynthesizer.cpp | 516 + .../Clang/ASTResultSynthesizer.h | 215 + .../Clang/ASTStructExtractor.cpp | 186 + .../Clang/ASTStructExtractor.h | 164 + .../ExpressionParser/Clang/CMakeLists.txt | 48 + .../ExpressionParser/Clang/ClangASTSource.cpp | 2012 +++ .../ExpressionParser/Clang/ClangASTSource.h | 510 + .../ExpressionParser/Clang/ClangDiagnostic.h | 50 + .../Clang/ClangExpressionDeclMap.cpp | 2150 +++ .../Clang/ClangExpressionDeclMap.h | 621 + .../Clang/ClangExpressionHelper.h | 73 + .../Clang/ClangExpressionParser.cpp | 986 ++ .../Clang/ClangExpressionParser.h | 166 + .../Clang/ClangExpressionVariable.cpp | 67 + .../Clang/ClangExpressionVariable.h | 240 + .../Clang/ClangFunctionCaller.cpp | 226 + .../Clang/ClangFunctionCaller.h | 166 + .../Clang/ClangModulesDeclVendor.cpp | 682 + .../Clang/ClangModulesDeclVendor.h | 121 + .../Clang/ClangPersistentVariables.cpp | 86 + .../Clang/ClangPersistentVariables.h | 96 + .../Clang/ClangUserExpression.cpp | 689 + .../Clang/ClangUserExpression.h | 198 + .../Clang/ClangUtilityFunction.cpp | 172 + .../Clang/ClangUtilityFunction.h | 115 + .../ExpressionParser/Clang/IRForTarget.cpp | 2274 +++ .../ExpressionParser/Clang/IRForTarget.h | 668 + .../ExpressionParser/Go/CMakeLists.txt | 13 + source/Plugins/ExpressionParser/Go/GoAST.h | 1977 +++ .../Plugins/ExpressionParser/Go/GoLexer.cpp | 350 + source/Plugins/ExpressionParser/Go/GoLexer.h | 181 + .../Plugins/ExpressionParser/Go/GoParser.cpp | 880 + source/Plugins/ExpressionParser/Go/GoParser.h | 145 + .../ExpressionParser/Go/GoUserExpression.cpp | 678 + .../ExpressionParser/Go/GoUserExpression.h | 92 + .../Plugins/ExpressionParser/Go/gen_go_ast.py | 464 + source/Plugins/Instruction/ARM/CMakeLists.txt | 14 + .../Instruction/ARM/EmulateInstructionARM.cpp | 14657 ++++++++++++++++ .../Instruction/ARM/EmulateInstructionARM.h | 787 + .../Instruction/ARM/EmulationStateARM.cpp | 356 + .../Instruction/ARM/EmulationStateARM.h | 80 + .../Plugins/Instruction/ARM64/CMakeLists.txt | 11 + .../ARM64/EmulateInstructionARM64.cpp | 1223 ++ .../ARM64/EmulateInstructionARM64.h | 205 + source/Plugins/Instruction/CMakeLists.txt | 4 + .../Plugins/Instruction/MIPS/CMakeLists.txt | 18 + .../MIPS/EmulateInstructionMIPS.cpp | 3130 ++++ .../Instruction/MIPS/EmulateInstructionMIPS.h | 219 + .../Plugins/Instruction/MIPS64/CMakeLists.txt | 18 + .../MIPS64/EmulateInstructionMIPS64.cpp | 2375 +++ .../MIPS64/EmulateInstructionMIPS64.h | 187 + .../ASan/ASanRuntime.cpp | 327 + .../InstrumentationRuntime/ASan/ASanRuntime.h | 71 + .../ASan/CMakeLists.txt | 13 + .../InstrumentationRuntime/CMakeLists.txt | 4 + .../MainThreadChecker/CMakeLists.txt | 13 + .../MainThreadCheckerRuntime.cpp | 276 + .../MainThreadCheckerRuntime.h | 68 + .../TSan/CMakeLists.txt | 12 + .../TSan/TSanRuntime.cpp | 1070 ++ .../InstrumentationRuntime/TSan/TSanRuntime.h | 86 + .../UBSan/CMakeLists.txt | 13 + .../UBSan/UBSanRuntime.cpp | 343 + .../UBSan/UBSanRuntime.h | 69 + source/Plugins/JITLoader/CMakeLists.txt | 1 + source/Plugins/JITLoader/GDB/CMakeLists.txt | 16 + source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp | 456 + source/Plugins/JITLoader/GDB/JITLoaderGDB.h | 91 + source/Plugins/Language/CMakeLists.txt | 6 + .../Language/CPlusPlus/BlockPointer.cpp | 211 + .../Plugins/Language/CPlusPlus/BlockPointer.h | 26 + .../Plugins/Language/CPlusPlus/CMakeLists.txt | 26 + .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 959 + .../Language/CPlusPlus/CPlusPlusLanguage.h | 138 + .../CPlusPlus/CPlusPlusNameParser.cpp | 661 + .../Language/CPlusPlus/CPlusPlusNameParser.h | 182 + .../Language/CPlusPlus/CxxStringTypes.cpp | 223 + .../Language/CPlusPlus/CxxStringTypes.h | 44 + source/Plugins/Language/CPlusPlus/LibCxx.cpp | 588 + source/Plugins/Language/CPlusPlus/LibCxx.h | 125 + .../Language/CPlusPlus/LibCxxAtomic.cpp | 105 + .../Plugins/Language/CPlusPlus/LibCxxAtomic.h | 31 + .../CPlusPlus/LibCxxInitializerList.cpp | 129 + .../Plugins/Language/CPlusPlus/LibCxxList.cpp | 359 + .../Plugins/Language/CPlusPlus/LibCxxMap.cpp | 469 + .../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 227 + .../Language/CPlusPlus/LibCxxVector.cpp | 298 + .../Plugins/Language/CPlusPlus/LibStdcpp.cpp | 431 + source/Plugins/Language/CPlusPlus/LibStdcpp.h | 60 + .../Language/CPlusPlus/LibStdcppTuple.cpp | 107 + .../CPlusPlus/LibStdcppUniquePointer.cpp | 150 + source/Plugins/Language/Go/CMakeLists.txt | 13 + .../Language/Go/GoFormatterFunctions.cpp | 152 + .../Language/Go/GoFormatterFunctions.h | 43 + source/Plugins/Language/Go/GoLanguage.cpp | 127 + source/Plugins/Language/Go/GoLanguage.h | 63 + source/Plugins/Language/Java/CMakeLists.txt | 12 + .../Language/Java/JavaFormatterFunctions.cpp | 167 + .../Language/Java/JavaFormatterFunctions.h | 35 + source/Plugins/Language/Java/JavaLanguage.cpp | 101 + source/Plugins/Language/Java/JavaLanguage.h | 52 + source/Plugins/Language/OCaml/CMakeLists.txt | 12 + .../Plugins/Language/OCaml/OCamlLanguage.cpp | 63 + source/Plugins/Language/OCaml/OCamlLanguage.h | 51 + source/Plugins/Language/ObjC/CF.cpp | 303 + source/Plugins/Language/ObjC/CF.h | 33 + source/Plugins/Language/ObjC/CMakeLists.txt | 24 + source/Plugins/Language/ObjC/Cocoa.cpp | 1036 ++ source/Plugins/Language/ObjC/Cocoa.h | 113 + source/Plugins/Language/ObjC/CoreMedia.cpp | 96 + source/Plugins/Language/ObjC/CoreMedia.h | 26 + source/Plugins/Language/ObjC/NSArray.cpp | 969 + source/Plugins/Language/ObjC/NSDictionary.cpp | 958 + source/Plugins/Language/ObjC/NSDictionary.h | 95 + source/Plugins/Language/ObjC/NSError.cpp | 219 + source/Plugins/Language/ObjC/NSException.cpp | 215 + source/Plugins/Language/ObjC/NSIndexPath.cpp | 324 + source/Plugins/Language/ObjC/NSSet.cpp | 648 + source/Plugins/Language/ObjC/NSSet.h | 40 + source/Plugins/Language/ObjC/NSString.cpp | 405 + source/Plugins/Language/ObjC/NSString.h | 42 + source/Plugins/Language/ObjC/ObjCLanguage.cpp | 1101 ++ source/Plugins/Language/ObjC/ObjCLanguage.h | 165 + .../Language/ObjCPlusPlus/CMakeLists.txt | 7 + .../ObjCPlusPlus/ObjCPlusPlusLanguage.cpp | 52 + .../ObjCPlusPlus/ObjCPlusPlusLanguage.h | 53 + source/Plugins/LanguageRuntime/CMakeLists.txt | 5 + .../LanguageRuntime/CPlusPlus/CMakeLists.txt | 2 + .../CPlusPlus/ItaniumABI/CMakeLists.txt | 10 + .../ItaniumABI/ItaniumABILanguageRuntime.cpp | 573 + .../ItaniumABI/ItaniumABILanguageRuntime.h | 115 + .../Plugins/LanguageRuntime/Go/CMakeLists.txt | 13 + .../LanguageRuntime/Go/GoLanguageRuntime.cpp | 215 + .../LanguageRuntime/Go/GoLanguageRuntime.h | 86 + .../LanguageRuntime/Java/CMakeLists.txt | 10 + .../Java/JavaLanguageRuntime.cpp | 157 + .../Java/JavaLanguageRuntime.h | 78 + .../AppleObjCClassDescriptorV2.cpp | 550 + .../AppleObjCClassDescriptorV2.h | 335 + .../AppleObjCRuntime/AppleObjCDeclVendor.cpp | 655 + .../AppleObjCRuntime/AppleObjCDeclVendor.h | 53 + .../AppleObjCRuntime/AppleObjCRuntime.cpp | 489 + .../ObjC/AppleObjCRuntime/AppleObjCRuntime.h | 127 + .../AppleObjCRuntime/AppleObjCRuntimeV1.cpp | 441 + .../AppleObjCRuntime/AppleObjCRuntimeV1.h | 161 + .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 2457 +++ .../AppleObjCRuntime/AppleObjCRuntimeV2.h | 331 + .../AppleObjCTrampolineHandler.cpp | 1150 ++ .../AppleObjCTrampolineHandler.h | 162 + .../AppleObjCTypeEncodingParser.cpp | 396 + .../AppleObjCTypeEncodingParser.h | 87 + ...pleThreadPlanStepThroughObjCTrampoline.cpp | 213 + ...AppleThreadPlanStepThroughObjCTrampoline.h | 81 + .../ObjC/AppleObjCRuntime/CMakeLists.txt | 24 + .../LanguageRuntime/ObjC/CMakeLists.txt | 1 + .../RenderScript/CMakeLists.txt | 1 + .../RenderScriptRuntime/CMakeLists.txt | 30 + .../RenderScriptExpressionOpts.cpp | 200 + .../RenderScriptExpressionOpts.h | 57 + .../RenderScriptRuntime.cpp | 5065 ++++++ .../RenderScriptRuntime/RenderScriptRuntime.h | 587 + .../RenderScriptScriptGroup.cpp | 161 + .../RenderScriptScriptGroup.h | 18 + .../RenderScriptx86ABIFixups.cpp | 297 + .../RenderScriptx86ABIFixups.h | 23 + source/Plugins/MemoryHistory/CMakeLists.txt | 1 + .../Plugins/MemoryHistory/asan/CMakeLists.txt | 9 + .../MemoryHistory/asan/MemoryHistoryASan.cpp | 204 + .../MemoryHistory/asan/MemoryHistoryASan.h | 53 + .../BSD-Archive/CMakeLists.txt | 10 + .../BSD-Archive/ObjectContainerBSDArchive.cpp | 521 + .../BSD-Archive/ObjectContainerBSDArchive.h | 179 + source/Plugins/ObjectContainer/CMakeLists.txt | 2 + .../Universal-Mach-O/CMakeLists.txt | 10 + .../ObjectContainerUniversalMachO.cpp | 239 + .../ObjectContainerUniversalMachO.h | 86 + source/Plugins/ObjectFile/CMakeLists.txt | 4 + source/Plugins/ObjectFile/ELF/CMakeLists.txt | 13 + source/Plugins/ObjectFile/ELF/ELFHeader.cpp | 448 + source/Plugins/ObjectFile/ELF/ELFHeader.h | 412 + .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 3406 ++++ source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 380 + source/Plugins/ObjectFile/JIT/CMakeLists.txt | 11 + .../Plugins/ObjectFile/JIT/ObjectFileJIT.cpp | 267 + source/Plugins/ObjectFile/JIT/ObjectFileJIT.h | 113 + .../Plugins/ObjectFile/Mach-O/CMakeLists.txt | 13 + .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 6268 +++++++ .../ObjectFile/Mach-O/ObjectFileMachO.h | 210 + .../Plugins/ObjectFile/PECOFF/CMakeLists.txt | 13 + .../ObjectFile/PECOFF/ObjectFilePECOFF.cpp | 1051 ++ .../ObjectFile/PECOFF/ObjectFilePECOFF.h | 287 + .../ObjectFile/PECOFF/WindowsMiniDump.cpp | 59 + .../ObjectFile/PECOFF/WindowsMiniDump.h | 23 + source/Plugins/OperatingSystem/CMakeLists.txt | 2 + .../Plugins/OperatingSystem/Go/CMakeLists.txt | 10 + .../OperatingSystem/Go/OperatingSystemGo.cpp | 499 + .../OperatingSystem/Go/OperatingSystemGo.h | 90 + .../OperatingSystem/Python/CMakeLists.txt | 10 + .../Python/OperatingSystemPython.cpp | 417 + .../Python/OperatingSystemPython.h | 98 + source/Plugins/Platform/Android/AdbClient.cpp | 654 + source/Plugins/Platform/Android/AdbClient.h | 141 + .../Plugins/Platform/Android/CMakeLists.txt | 13 + .../Platform/Android/PlatformAndroid.cpp | 389 + .../Platform/Android/PlatformAndroid.h | 94 + .../PlatformAndroidRemoteGDBServer.cpp | 234 + .../Android/PlatformAndroidRemoteGDBServer.h | 68 + source/Plugins/Platform/CMakeLists.txt | 18 + .../Plugins/Platform/FreeBSD/CMakeLists.txt | 9 + .../Platform/FreeBSD/PlatformFreeBSD.cpp | 326 + .../Platform/FreeBSD/PlatformFreeBSD.h | 74 + .../Plugins/Platform/Kalimba/CMakeLists.txt | 8 + .../Platform/Kalimba/PlatformKalimba.cpp | 157 + .../Platform/Kalimba/PlatformKalimba.h | 79 + source/Plugins/Platform/Linux/CMakeLists.txt | 11 + .../Plugins/Platform/Linux/PlatformLinux.cpp | 411 + source/Plugins/Platform/Linux/PlatformLinux.h | 72 + source/Plugins/Platform/MacOSX/CMakeLists.txt | 43 + .../MacOSX/PlatformAppleSimulator.cpp | 270 + .../Platform/MacOSX/PlatformAppleSimulator.h | 72 + .../MacOSX/PlatformAppleTVSimulator.cpp | 395 + .../MacOSX/PlatformAppleTVSimulator.h | 99 + .../MacOSX/PlatformAppleWatchSimulator.cpp | 396 + .../MacOSX/PlatformAppleWatchSimulator.h | 99 + .../Platform/MacOSX/PlatformDarwin.cpp | 1842 ++ .../Plugins/Platform/MacOSX/PlatformDarwin.h | 145 + .../Platform/MacOSX/PlatformDarwinKernel.cpp | 856 + .../Platform/MacOSX/PlatformDarwinKernel.h | 209 + .../Platform/MacOSX/PlatformMacOSX.cpp | 347 + .../Plugins/Platform/MacOSX/PlatformMacOSX.h | 92 + .../Platform/MacOSX/PlatformRemoteAppleTV.cpp | 250 + .../Platform/MacOSX/PlatformRemoteAppleTV.h | 77 + .../MacOSX/PlatformRemoteAppleWatch.cpp | 307 + .../MacOSX/PlatformRemoteAppleWatch.h | 82 + .../MacOSX/PlatformRemoteDarwinDevice.cpp | 654 + .../MacOSX/PlatformRemoteDarwinDevice.h | 118 + .../Platform/MacOSX/PlatformRemoteiOS.cpp | 165 + .../Platform/MacOSX/PlatformRemoteiOS.h | 76 + .../Platform/MacOSX/PlatformiOSSimulator.cpp | 425 + .../Platform/MacOSX/PlatformiOSSimulator.h | 99 + ...PlatformiOSSimulatorCoreSimulatorSupport.h | 225 + ...latformiOSSimulatorCoreSimulatorSupport.mm | 644 + source/Plugins/Platform/NetBSD/CMakeLists.txt | 9 + .../Platform/NetBSD/PlatformNetBSD.cpp | 432 + .../Plugins/Platform/NetBSD/PlatformNetBSD.h | 72 + .../Plugins/Platform/OpenBSD/CMakeLists.txt | 9 + .../Platform/OpenBSD/PlatformOpenBSD.cpp | 223 + .../Platform/OpenBSD/PlatformOpenBSD.h | 66 + source/Plugins/Platform/POSIX/CMakeLists.txt | 10 + .../Plugins/Platform/POSIX/PlatformPOSIX.cpp | 1050 ++ source/Plugins/Platform/POSIX/PlatformPOSIX.h | 210 + .../Plugins/Platform/Windows/CMakeLists.txt | 9 + .../Platform/Windows/PlatformWindows.cpp | 607 + .../Platform/Windows/PlatformWindows.h | 137 + .../Platform/gdb-server/CMakeLists.txt | 10 + .../gdb-server/PlatformRemoteGDBServer.cpp | 890 + .../gdb-server/PlatformRemoteGDBServer.h | 210 + source/Plugins/Process/CMakeLists.txt | 19 + source/Plugins/Process/Darwin/CFBundle.cpp | 79 + source/Plugins/Process/Darwin/CFBundle.h | 38 + source/Plugins/Process/Darwin/CFString.cpp | 163 + source/Plugins/Process/Darwin/CFString.h | 43 + source/Plugins/Process/Darwin/CFUtils.h | 78 + .../Process/Darwin/DarwinProcessLauncher.cpp | 651 + .../Process/Darwin/DarwinProcessLauncher.h | 49 + source/Plugins/Process/Darwin/LaunchFlavor.h | 33 + .../Plugins/Process/Darwin/MachException.cpp | 543 + source/Plugins/Process/Darwin/MachException.h | 140 + .../Process/Darwin/NativeProcessDarwin.cpp | 1566 ++ .../Process/Darwin/NativeProcessDarwin.h | 385 + .../Process/Darwin/NativeThreadDarwin.cpp | 284 + .../Process/Darwin/NativeThreadDarwin.h | 178 + .../Process/Darwin/NativeThreadListDarwin.cpp | 698 + .../Process/Darwin/NativeThreadListDarwin.h | 139 + source/Plugins/Process/FreeBSD/CMakeLists.txt | 28 + .../Plugins/Process/FreeBSD/FreeBSDThread.cpp | 654 + .../Plugins/Process/FreeBSD/FreeBSDThread.h | 123 + .../Plugins/Process/FreeBSD/POSIXStopInfo.cpp | 61 + .../Plugins/Process/FreeBSD/POSIXStopInfo.h | 80 + .../Process/FreeBSD/ProcessFreeBSD.cpp | 1121 ++ .../Plugins/Process/FreeBSD/ProcessFreeBSD.h | 230 + .../Process/FreeBSD/ProcessMonitor.cpp | 1450 ++ .../Plugins/Process/FreeBSD/ProcessMonitor.h | 284 + .../Process/FreeBSD/RegisterContextPOSIX.h | 68 + ...RegisterContextPOSIXProcessMonitor_arm.cpp | 260 + .../RegisterContextPOSIXProcessMonitor_arm.h | 77 + ...gisterContextPOSIXProcessMonitor_arm64.cpp | 265 + ...RegisterContextPOSIXProcessMonitor_arm64.h | 78 + ...isterContextPOSIXProcessMonitor_mips64.cpp | 263 + ...egisterContextPOSIXProcessMonitor_mips64.h | 81 + ...sterContextPOSIXProcessMonitor_powerpc.cpp | 275 + ...gisterContextPOSIXProcessMonitor_powerpc.h | 85 + ...RegisterContextPOSIXProcessMonitor_x86.cpp | 614 + .../RegisterContextPOSIXProcessMonitor_x86.h | 80 + source/Plugins/Process/Linux/CMakeLists.txt | 27 + .../Process/Linux/NativeProcessLinux.cpp | 2576 +++ .../Process/Linux/NativeProcessLinux.h | 288 + .../Linux/NativeRegisterContextLinux.cpp | 204 + .../Linux/NativeRegisterContextLinux.h | 92 + .../Linux/NativeRegisterContextLinux_arm.cpp | 983 ++ .../Linux/NativeRegisterContextLinux_arm.h | 170 + .../NativeRegisterContextLinux_arm64.cpp | 999 ++ .../Linux/NativeRegisterContextLinux_arm64.h | 170 + .../NativeRegisterContextLinux_mips64.cpp | 1059 ++ .../Linux/NativeRegisterContextLinux_mips64.h | 140 + .../NativeRegisterContextLinux_s390x.cpp | 640 + .../Linux/NativeRegisterContextLinux_s390x.h | 116 + .../NativeRegisterContextLinux_x86_64.cpp | 1207 ++ .../Linux/NativeRegisterContextLinux_x86_64.h | 147 + .../Process/Linux/NativeThreadLinux.cpp | 465 + .../Plugins/Process/Linux/NativeThreadLinux.h | 118 + .../Plugins/Process/Linux/ProcessorTrace.cpp | 395 + source/Plugins/Process/Linux/ProcessorTrace.h | 141 + source/Plugins/Process/Linux/Procfs.h | 31 + .../Plugins/Process/Linux/SingleStepCheck.cpp | 182 + .../Plugins/Process/Linux/SingleStepCheck.h | 57 + .../Process/MacOSX-Kernel/CMakeLists.txt | 22 + .../MacOSX-Kernel/CommunicationKDP.cpp | 1342 ++ .../Process/MacOSX-Kernel/CommunicationKDP.h | 264 + .../Process/MacOSX-Kernel/ProcessKDP.cpp | 1042 ++ .../Process/MacOSX-Kernel/ProcessKDP.h | 223 + .../Process/MacOSX-Kernel/ProcessKDPLog.cpp | 35 + .../Process/MacOSX-Kernel/ProcessKDPLog.h | 43 + .../MacOSX-Kernel/RegisterContextKDP_arm.cpp | 151 + .../MacOSX-Kernel/RegisterContextKDP_arm.h | 48 + .../RegisterContextKDP_arm64.cpp | 152 + .../MacOSX-Kernel/RegisterContextKDP_arm64.h | 49 + .../MacOSX-Kernel/RegisterContextKDP_i386.cpp | 119 + .../MacOSX-Kernel/RegisterContextKDP_i386.h | 43 + .../RegisterContextKDP_x86_64.cpp | 122 + .../MacOSX-Kernel/RegisterContextKDP_x86_64.h | 43 + .../Process/MacOSX-Kernel/ThreadKDP.cpp | 170 + .../Plugins/Process/MacOSX-Kernel/ThreadKDP.h | 77 + source/Plugins/Process/NetBSD/CMakeLists.txt | 21 + .../Process/NetBSD/NativeProcessNetBSD.cpp | 939 + .../Process/NetBSD/NativeProcessNetBSD.h | 144 + .../NetBSD/NativeRegisterContextNetBSD.cpp | 112 + .../NetBSD/NativeRegisterContextNetBSD.h | 74 + .../NativeRegisterContextNetBSD_x86_64.cpp | 940 + .../NativeRegisterContextNetBSD_x86_64.h | 96 + .../Process/NetBSD/NativeThreadNetBSD.cpp | 218 + .../Process/NetBSD/NativeThreadNetBSD.h | 81 + source/Plugins/Process/POSIX/CMakeLists.txt | 13 + source/Plugins/Process/POSIX/CrashReason.cpp | 339 + source/Plugins/Process/POSIX/CrashReason.h | 60 + .../Plugins/Process/POSIX/ProcessMessage.cpp | 69 + source/Plugins/Process/POSIX/ProcessMessage.h | 169 + .../Plugins/Process/POSIX/ProcessPOSIXLog.cpp | 32 + .../Plugins/Process/POSIX/ProcessPOSIXLog.h | 44 + source/Plugins/Process/Utility/ARMDefines.h | 191 + source/Plugins/Process/Utility/ARMUtils.h | 375 + source/Plugins/Process/Utility/CMakeLists.txt | 64 + .../Process/Utility/DynamicRegisterInfo.cpp | 747 + .../Process/Utility/DynamicRegisterInfo.h | 93 + .../Process/Utility/FreeBSDSignals.cpp | 91 + .../Plugins/Process/Utility/FreeBSDSignals.h | 29 + .../Process/Utility/GDBRemoteSignals.cpp | 22 + .../Process/Utility/GDBRemoteSignals.h | 34 + .../Plugins/Process/Utility/HistoryThread.cpp | 83 + .../Plugins/Process/Utility/HistoryThread.h | 102 + .../Plugins/Process/Utility/HistoryUnwind.cpp | 67 + .../Plugins/Process/Utility/HistoryUnwind.h | 48 + .../Process/Utility/InferiorCallPOSIX.cpp | 240 + .../Process/Utility/InferiorCallPOSIX.h | 39 + .../Process/Utility/InstructionUtils.h | 114 + .../Plugins/Process/Utility/LinuxSignals.cpp | 96 + source/Plugins/Process/Utility/LinuxSignals.h | 32 + .../Process/Utility/MipsLinuxSignals.cpp | 97 + .../Process/Utility/MipsLinuxSignals.h | 33 + .../NativeRegisterContextRegisterInfo.cpp | 43 + .../NativeRegisterContextRegisterInfo.h | 41 + .../Plugins/Process/Utility/NetBSDSignals.cpp | 58 + .../Plugins/Process/Utility/NetBSDSignals.h | 29 + .../Utility/RegisterContextDarwin_arm.cpp | 1770 ++ .../Utility/RegisterContextDarwin_arm.h | 269 + .../Utility/RegisterContextDarwin_arm64.cpp | 1047 ++ .../Utility/RegisterContextDarwin_arm64.h | 236 + .../Utility/RegisterContextDarwin_i386.cpp | 981 ++ .../Utility/RegisterContextDarwin_i386.h | 213 + .../Utility/RegisterContextDarwin_x86_64.cpp | 1084 ++ .../Utility/RegisterContextDarwin_x86_64.h | 218 + .../Process/Utility/RegisterContextDummy.cpp | 121 + .../Process/Utility/RegisterContextDummy.h | 71 + .../Utility/RegisterContextFreeBSD_i386.cpp | 83 + .../Utility/RegisterContextFreeBSD_i386.h | 26 + .../Utility/RegisterContextFreeBSD_mips64.cpp | 120 + .../Utility/RegisterContextFreeBSD_mips64.h | 31 + .../RegisterContextFreeBSD_powerpc.cpp | 239 + .../Utility/RegisterContextFreeBSD_powerpc.h | 57 + .../Utility/RegisterContextFreeBSD_x86_64.cpp | 148 + .../Utility/RegisterContextFreeBSD_x86_64.h | 31 + .../Utility/RegisterContextHistory.cpp | 123 + .../Process/Utility/RegisterContextHistory.h | 72 + .../Process/Utility/RegisterContextLLDB.cpp | 2116 +++ .../Process/Utility/RegisterContextLLDB.h | 265 + .../Utility/RegisterContextLinux_i386.cpp | 136 + .../Utility/RegisterContextLinux_i386.h | 34 + .../Utility/RegisterContextLinux_mips.cpp | 152 + .../Utility/RegisterContextLinux_mips.h | 37 + .../Utility/RegisterContextLinux_mips64.cpp | 212 + .../Utility/RegisterContextLinux_mips64.h | 40 + .../Utility/RegisterContextLinux_s390x.cpp | 77 + .../Utility/RegisterContextLinux_s390x.h | 37 + .../Utility/RegisterContextLinux_x86_64.cpp | 197 + .../Utility/RegisterContextLinux_x86_64.h | 37 + .../RegisterContextMacOSXFrameBackchain.cpp | 169 + .../RegisterContextMacOSXFrameBackchain.h | 61 + .../Utility/RegisterContextMach_arm.cpp | 71 + .../Process/Utility/RegisterContextMach_arm.h | 45 + .../Utility/RegisterContextMach_i386.cpp | 59 + .../Utility/RegisterContextMach_i386.h | 40 + .../Utility/RegisterContextMach_x86_64.cpp | 62 + .../Utility/RegisterContextMach_x86_64.h | 41 + .../Process/Utility/RegisterContextMemory.cpp | 148 + .../Process/Utility/RegisterContextMemory.h | 80 + .../Utility/RegisterContextNetBSD_x86_64.cpp | 126 + .../Utility/RegisterContextNetBSD_x86_64.h | 31 + .../Utility/RegisterContextOpenBSD_i386.cpp | 80 + .../Utility/RegisterContextOpenBSD_i386.h | 26 + .../Utility/RegisterContextOpenBSD_x86_64.cpp | 107 + .../Utility/RegisterContextOpenBSD_x86_64.h | 31 + .../Utility/RegisterContextPOSIX_arm.cpp | 218 + .../Utility/RegisterContextPOSIX_arm.h | 111 + .../Utility/RegisterContextPOSIX_arm64.cpp | 238 + .../Utility/RegisterContextPOSIX_arm64.h | 111 + .../Utility/RegisterContextPOSIX_mips64.cpp | 190 + .../Utility/RegisterContextPOSIX_mips64.h | 89 + .../Utility/RegisterContextPOSIX_powerpc.cpp | 199 + .../Utility/RegisterContextPOSIX_powerpc.h | 209 + .../Utility/RegisterContextPOSIX_s390x.cpp | 192 + .../Utility/RegisterContextPOSIX_s390x.h | 84 + .../Utility/RegisterContextPOSIX_x86.cpp | 555 + .../Utility/RegisterContextPOSIX_x86.h | 183 + .../Utility/RegisterContextThreadMemory.cpp | 219 + .../Utility/RegisterContextThreadMemory.h | 105 + .../Process/Utility/RegisterContext_mips.h | 380 + .../Process/Utility/RegisterContext_powerpc.h | 124 + .../Process/Utility/RegisterContext_s390x.h | 93 + .../Process/Utility/RegisterContext_x86.h | 358 + .../Process/Utility/RegisterInfoInterface.h | 74 + .../Process/Utility/RegisterInfoPOSIX_arm.cpp | 94 + .../Process/Utility/RegisterInfoPOSIX_arm.h | 62 + .../Utility/RegisterInfoPOSIX_arm64.cpp | 99 + .../Process/Utility/RegisterInfoPOSIX_arm64.h | 70 + .../Process/Utility/RegisterInfos_arm.h | 1624 ++ .../Process/Utility/RegisterInfos_arm64.h | 717 + .../Process/Utility/RegisterInfos_i386.h | 307 + .../Process/Utility/RegisterInfos_mips.h | 310 + .../Process/Utility/RegisterInfos_mips64.h | 440 + .../Process/Utility/RegisterInfos_powerpc.h | 229 + .../Process/Utility/RegisterInfos_s390x.h | 129 + .../Process/Utility/RegisterInfos_x86_64.h | 470 + .../Process/Utility/StopInfoMachException.cpp | 584 + .../Process/Utility/StopInfoMachException.h | 58 + .../Plugins/Process/Utility/ThreadMemory.cpp | 101 + source/Plugins/Process/Utility/ThreadMemory.h | 111 + source/Plugins/Process/Utility/UnwindLLDB.cpp | 538 + source/Plugins/Process/Utility/UnwindLLDB.h | 167 + .../Utility/UnwindMacOSXFrameBackchain.cpp | 254 + .../Utility/UnwindMacOSXFrameBackchain.h | 60 + .../Process/Utility/lldb-arm-register-enums.h | 202 + .../Utility/lldb-arm64-register-enums.h | 267 + .../lldb-mips-freebsd-register-enums.h | 68 + .../Utility/lldb-mips-linux-register-enums.h | 365 + .../Utility/lldb-s390x-register-enums.h | 93 + .../Process/Utility/lldb-x86-register-enums.h | 323 + .../Process/Windows/Common/CMakeLists.txt | 36 + .../Process/Windows/Common/DebuggerThread.cpp | 522 + .../Process/Windows/Common/DebuggerThread.h | 106 + .../Process/Windows/Common/ExceptionRecord.h | 80 + .../Process/Windows/Common/ForwardDecl.h | 42 + .../Process/Windows/Common/IDebugDelegate.h | 46 + .../Windows/Common/LocalDebugDelegate.cpp | 73 + .../Windows/Common/LocalDebugDelegate.h | 67 + .../Process/Windows/Common/NtStructures.h | 31 + .../Process/Windows/Common/ProcessWindows.cpp | 1021 ++ .../Process/Windows/Common/ProcessWindows.h | 119 + .../Windows/Common/ProcessWindowsLog.cpp | 41 + .../Windows/Common/ProcessWindowsLog.h | 36 + .../Windows/Common/RegisterContextWindows.cpp | 135 + .../Windows/Common/RegisterContextWindows.h | 67 + .../Windows/Common/TargetThreadWindows.cpp | 125 + .../Windows/Common/TargetThreadWindows.h | 51 + .../Common/x64/RegisterContextWindows_x64.cpp | 342 + .../Common/x64/RegisterContextWindows_x64.h | 48 + .../Common/x86/RegisterContextWindows_x86.cpp | 288 + .../Common/x86/RegisterContextWindows_x86.h | 52 + .../Plugins/Process/elf-core/CMakeLists.txt | 22 + .../Process/elf-core/ProcessElfCore.cpp | 758 + .../Plugins/Process/elf-core/ProcessElfCore.h | 175 + .../elf-core/RegisterContextPOSIXCore_arm.cpp | 71 + .../elf-core/RegisterContextPOSIXCore_arm.h | 57 + .../RegisterContextPOSIXCore_arm64.cpp | 71 + .../elf-core/RegisterContextPOSIXCore_arm64.h | 57 + .../RegisterContextPOSIXCore_mips64.cpp | 87 + .../RegisterContextPOSIXCore_mips64.h | 59 + .../RegisterContextPOSIXCore_powerpc.cpp | 106 + .../RegisterContextPOSIXCore_powerpc.h | 65 + .../RegisterContextPOSIXCore_s390x.cpp | 93 + .../elf-core/RegisterContextPOSIXCore_s390x.h | 59 + .../RegisterContextPOSIXCore_x86_64.cpp | 98 + .../RegisterContextPOSIXCore_x86_64.h | 53 + .../Process/elf-core/ThreadElfCore.cpp | 433 + .../Plugins/Process/elf-core/ThreadElfCore.h | 186 + .../Plugins/Process/gdb-remote/CMakeLists.txt | 35 + .../gdb-remote/GDBRemoteClientBase.cpp | 376 + .../Process/gdb-remote/GDBRemoteClientBase.h | 144 + .../gdb-remote/GDBRemoteCommunication.cpp | 1377 ++ .../gdb-remote/GDBRemoteCommunication.h | 293 + .../GDBRemoteCommunicationClient.cpp | 3894 ++++ .../gdb-remote/GDBRemoteCommunicationClient.h | 621 + .../GDBRemoteCommunicationServer.cpp | 144 + .../gdb-remote/GDBRemoteCommunicationServer.h | 83 + .../GDBRemoteCommunicationServerCommon.cpp | 1296 ++ .../GDBRemoteCommunicationServerCommon.h | 162 + .../GDBRemoteCommunicationServerLLGS.cpp | 3316 ++++ .../GDBRemoteCommunicationServerLLGS.h | 264 + .../GDBRemoteCommunicationServerPlatform.cpp | 567 + .../GDBRemoteCommunicationServerPlatform.h | 116 + .../gdb-remote/GDBRemoteRegisterContext.cpp | 986 ++ .../gdb-remote/GDBRemoteRegisterContext.h | 137 + .../Process/gdb-remote/ProcessGDBRemote.cpp | 5227 ++++++ .../Process/gdb-remote/ProcessGDBRemote.h | 471 + .../gdb-remote/ProcessGDBRemoteLog.cpp | 44 + .../Process/gdb-remote/ProcessGDBRemoteLog.h | 51 + .../Process/gdb-remote/ThreadGDBRemote.cpp | 350 + .../Process/gdb-remote/ThreadGDBRemote.h | 123 + .../Plugins/Process/mach-core/CMakeLists.txt | 19 + .../Process/mach-core/ProcessMachCore.cpp | 661 + .../Process/mach-core/ProcessMachCore.h | 153 + .../Process/mach-core/ThreadMachCore.cpp | 105 + .../Process/mach-core/ThreadMachCore.h | 74 + .../Plugins/Process/minidump/CMakeLists.txt | 19 + .../Process/minidump/MinidumpParser.cpp | 458 + .../Plugins/Process/minidump/MinidumpParser.h | 102 + .../Process/minidump/MinidumpTypes.cpp | 235 + .../Plugins/Process/minidump/MinidumpTypes.h | 470 + .../Plugins/Process/minidump/NtStructures.h | 37 + .../Process/minidump/ProcessMinidump.cpp | 309 + .../Process/minidump/ProcessMinidump.h | 105 + .../RegisterContextMinidump_x86_32.cpp | 99 + .../minidump/RegisterContextMinidump_x86_32.h | 138 + .../RegisterContextMinidump_x86_64.cpp | 113 + .../minidump/RegisterContextMinidump_x86_64.h | 183 + .../Process/minidump/ThreadMinidump.cpp | 114 + .../Plugins/Process/minidump/ThreadMinidump.h | 52 + .../Plugins/ScriptInterpreter/CMakeLists.txt | 2 + .../ScriptInterpreter/None/CMakeLists.txt | 7 + .../None/ScriptInterpreterNone.cpp | 73 + .../None/ScriptInterpreterNone.h | 57 + .../ScriptInterpreter/Python/CMakeLists.txt | 15 + .../Python/PythonDataObjects.cpp | 1050 ++ .../Python/PythonDataObjects.h | 474 + .../Python/PythonExceptionState.cpp | 171 + .../Python/PythonExceptionState.h | 57 + .../Python/ScriptInterpreterPython.cpp | 3186 ++++ .../Python/ScriptInterpreterPython.h | 570 + .../ScriptInterpreter/Python/lldb-python.h | 41 + source/Plugins/StructuredData/CMakeLists.txt | 2 + .../StructuredData/DarwinLog/CMakeLists.txt | 10 + .../DarwinLog/StructuredDataDarwinLog.cpp | 2021 +++ .../DarwinLog/StructuredDataDarwinLog.h | 139 + source/Plugins/SymbolFile/CMakeLists.txt | 3 + .../Plugins/SymbolFile/DWARF/CMakeLists.txt | 51 + source/Plugins/SymbolFile/DWARF/DIERef.cpp | 72 + source/Plugins/SymbolFile/DWARF/DIERef.h | 54 + .../Plugins/SymbolFile/DWARF/DWARFASTParser.h | 50 + .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 4157 +++++ .../SymbolFile/DWARF/DWARFASTParserClang.h | 161 + .../SymbolFile/DWARF/DWARFASTParserGo.cpp | 775 + .../SymbolFile/DWARF/DWARFASTParserGo.h | 84 + .../SymbolFile/DWARF/DWARFASTParserJava.cpp | 509 + .../SymbolFile/DWARF/DWARFASTParserJava.h | 81 + .../SymbolFile/DWARF/DWARFASTParserOCaml.cpp | 209 + .../SymbolFile/DWARF/DWARFASTParserOCaml.h | 60 + .../DWARF/DWARFAbbreviationDeclaration.cpp | 94 + .../DWARF/DWARFAbbreviationDeclaration.h | 75 + .../SymbolFile/DWARF/DWARFAttribute.cpp | 74 + .../Plugins/SymbolFile/DWARF/DWARFAttribute.h | 85 + .../SymbolFile/DWARF/DWARFCompileUnit.cpp | 1127 ++ .../SymbolFile/DWARF/DWARFCompileUnit.h | 223 + source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp | 468 + source/Plugins/SymbolFile/DWARF/DWARFDIE.h | 221 + .../SymbolFile/DWARF/DWARFDIECollection.cpp | 35 + .../SymbolFile/DWARF/DWARFDIECollection.h | 38 + .../SymbolFile/DWARF/DWARFDataExtractor.cpp | 27 + .../SymbolFile/DWARF/DWARFDataExtractor.h | 40 + .../SymbolFile/DWARF/DWARFDebugAbbrev.cpp | 177 + .../SymbolFile/DWARF/DWARFDebugAbbrev.h | 74 + .../SymbolFile/DWARF/DWARFDebugArangeSet.cpp | 270 + .../SymbolFile/DWARF/DWARFDebugArangeSet.h | 76 + .../SymbolFile/DWARF/DWARFDebugAranges.cpp | 151 + .../SymbolFile/DWARF/DWARFDebugAranges.h | 66 + .../SymbolFile/DWARF/DWARFDebugInfo.cpp | 586 + .../Plugins/SymbolFile/DWARF/DWARFDebugInfo.h | 91 + .../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 1840 ++ .../SymbolFile/DWARF/DWARFDebugInfoEntry.h | 307 + .../SymbolFile/DWARF/DWARFDebugLine.cpp | 1298 ++ .../Plugins/SymbolFile/DWARF/DWARFDebugLine.h | 242 + .../SymbolFile/DWARF/DWARFDebugMacinfo.cpp | 39 + .../SymbolFile/DWARF/DWARFDebugMacinfo.h | 26 + .../DWARF/DWARFDebugMacinfoEntry.cpp | 111 + .../SymbolFile/DWARF/DWARFDebugMacinfoEntry.h | 42 + .../SymbolFile/DWARF/DWARFDebugMacro.cpp | 127 + .../SymbolFile/DWARF/DWARFDebugMacro.h | 62 + .../SymbolFile/DWARF/DWARFDebugPubnames.cpp | 255 + .../SymbolFile/DWARF/DWARFDebugPubnames.h | 40 + .../DWARF/DWARFDebugPubnamesSet.cpp | 146 + .../SymbolFile/DWARF/DWARFDebugPubnamesSet.h | 95 + .../SymbolFile/DWARF/DWARFDebugRanges.cpp | 124 + .../SymbolFile/DWARF/DWARFDebugRanges.h | 40 + .../SymbolFile/DWARF/DWARFDeclContext.cpp | 88 + .../SymbolFile/DWARF/DWARFDeclContext.h | 95 + .../Plugins/SymbolFile/DWARF/DWARFDefines.cpp | 649 + .../Plugins/SymbolFile/DWARF/DWARFDefines.h | 113 + .../SymbolFile/DWARF/DWARFFormValue.cpp | 727 + .../Plugins/SymbolFile/DWARF/DWARFFormValue.h | 96 + .../SymbolFile/DWARF/HashedNameToDIE.cpp | 643 + .../SymbolFile/DWARF/HashedNameToDIE.h | 193 + .../SymbolFile/DWARF/LogChannelDWARF.cpp | 43 + .../SymbolFile/DWARF/LogChannelDWARF.h | 43 + source/Plugins/SymbolFile/DWARF/NameToDIE.cpp | 82 + source/Plugins/SymbolFile/DWARF/NameToDIE.h | 54 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 4290 +++++ .../SymbolFile/DWARF/SymbolFileDWARF.h | 528 + .../DWARF/SymbolFileDWARFDebugMap.cpp | 1443 ++ .../DWARF/SymbolFileDWARFDebugMap.h | 378 + .../SymbolFile/DWARF/SymbolFileDWARFDwo.cpp | 122 + .../SymbolFile/DWARF/SymbolFileDWARFDwo.h | 71 + .../SymbolFile/DWARF/UniqueDWARFASTType.cpp | 77 + .../SymbolFile/DWARF/UniqueDWARFASTType.h | 110 + source/Plugins/SymbolFile/PDB/CMakeLists.txt | 14 + .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 232 + source/Plugins/SymbolFile/PDB/PDBASTParser.h | 52 + .../Plugins/SymbolFile/PDB/SymbolFilePDB.cpp | 676 + source/Plugins/SymbolFile/PDB/SymbolFilePDB.h | 190 + .../Plugins/SymbolFile/Symtab/CMakeLists.txt | 7 + .../SymbolFile/Symtab/SymbolFileSymtab.cpp | 273 + .../SymbolFile/Symtab/SymbolFileSymtab.h | 115 + source/Plugins/SymbolVendor/CMakeLists.txt | 5 + .../Plugins/SymbolVendor/ELF/CMakeLists.txt | 8 + .../SymbolVendor/ELF/SymbolVendorELF.cpp | 168 + .../SymbolVendor/ELF/SymbolVendorELF.h | 55 + .../SymbolVendor/MacOSX/CMakeLists.txt | 10 + .../MacOSX/SymbolVendorMacOSX.cpp | 299 + .../SymbolVendor/MacOSX/SymbolVendorMacOSX.h | 51 + source/Plugins/SystemRuntime/CMakeLists.txt | 1 + .../MacOSX/AppleGetItemInfoHandler.cpp | 404 + .../MacOSX/AppleGetItemInfoHandler.h | 119 + .../MacOSX/AppleGetPendingItemsHandler.cpp | 413 + .../MacOSX/AppleGetPendingItemsHandler.h | 124 + .../MacOSX/AppleGetQueuesHandler.cpp | 411 + .../MacOSX/AppleGetQueuesHandler.h | 116 + .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 419 + .../MacOSX/AppleGetThreadItemInfoHandler.h | 118 + .../SystemRuntime/MacOSX/CMakeLists.txt | 17 + .../MacOSX/SystemRuntimeMacOSX.cpp | 1035 ++ .../MacOSX/SystemRuntimeMacOSX.h | 302 + source/Plugins/UnwindAssembly/CMakeLists.txt | 2 + .../InstEmulation/CMakeLists.txt | 8 + .../UnwindAssemblyInstEmulation.cpp | 666 + .../UnwindAssemblyInstEmulation.h | 161 + .../Plugins/UnwindAssembly/x86/CMakeLists.txt | 14 + .../UnwindAssembly/x86/UnwindAssembly-x86.cpp | 279 + .../UnwindAssembly/x86/UnwindAssembly-x86.h | 72 + .../x86/x86AssemblyInspectionEngine.cpp | 1241 ++ .../x86/x86AssemblyInspectionEngine.h | 182 + source/Symbol/ArmUnwindInfo.cpp | 371 + source/Symbol/Block.cpp | 505 + source/Symbol/CMakeLists.txt | 59 + source/Symbol/ClangASTContext.cpp | 10123 +++++++++++ source/Symbol/ClangASTImporter.cpp | 1117 ++ .../ClangExternalASTSourceCallbacks.cpp | 103 + .../Symbol/ClangExternalASTSourceCommon.cpp | 92 + source/Symbol/ClangUtil.cpp | 50 + source/Symbol/CompactUnwindInfo.cpp | 1627 ++ source/Symbol/CompileUnit.cpp | 434 + source/Symbol/CompilerDecl.cpp | 54 + source/Symbol/CompilerDeclContext.cpp | 73 + source/Symbol/CompilerType.cpp | 1071 ++ source/Symbol/DWARFCallFrameInfo.cpp | 1092 ++ source/Symbol/DebugMacros.cpp | 54 + source/Symbol/Declaration.cpp | 97 + source/Symbol/FuncUnwinders.cpp | 482 + source/Symbol/Function.cpp | 539 + source/Symbol/GoASTContext.cpp | 1447 ++ source/Symbol/JavaASTContext.cpp | 1333 ++ source/Symbol/LineEntry.cpp | 242 + source/Symbol/LineTable.cpp | 551 + source/Symbol/OCamlASTContext.cpp | 670 + source/Symbol/ObjectFile.cpp | 695 + source/Symbol/Symbol.cpp | 571 + source/Symbol/SymbolContext.cpp | 1406 ++ source/Symbol/SymbolFile.cpp | 156 + source/Symbol/SymbolVendor.cpp | 484 + source/Symbol/Symtab.cpp | 1176 ++ source/Symbol/Type.cpp | 1122 ++ source/Symbol/TypeList.cpp | 222 + source/Symbol/TypeMap.cpp | 266 + source/Symbol/TypeSystem.cpp | 247 + source/Symbol/UnwindPlan.cpp | 514 + source/Symbol/UnwindTable.cpp | 192 + source/Symbol/Variable.cpp | 777 + source/Symbol/VariableList.cpp | 181 + source/Symbol/VerifyDecl.cpp | 13 + source/Target/ABI.cpp | 214 + source/Target/CMakeLists.txt | 78 + source/Target/CPPLanguageRuntime.cpp | 42 + source/Target/ExecutionContext.cpp | 633 + source/Target/FileAction.cpp | 91 + source/Target/InstrumentationRuntime.cpp | 80 + .../Target/InstrumentationRuntimeStopInfo.cpp | 37 + source/Target/JITLoader.cpp | 37 + source/Target/JITLoaderList.cpp | 56 + source/Target/Language.cpp | 424 + source/Target/LanguageRuntime.cpp | 301 + source/Target/Memory.cpp | 421 + source/Target/MemoryHistory.cpp | 33 + source/Target/ModuleCache.cpp | 332 + source/Target/ObjCLanguageRuntime.cpp | 387 + source/Target/OperatingSystem.cpp | 59 + source/Target/PathMappingList.cpp | 291 + source/Target/Platform.cpp | 1894 ++ source/Target/Process.cpp | 6236 +++++++ source/Target/ProcessInfo.cpp | 121 + source/Target/ProcessLaunchInfo.cpp | 446 + source/Target/Queue.cpp | 94 + source/Target/QueueItem.cpp | 107 + source/Target/QueueList.cpp | 70 + source/Target/RegisterContext.cpp | 588 + source/Target/RegisterNumber.cpp | 119 + source/Target/SectionLoadHistory.cpp | 172 + source/Target/SectionLoadList.cpp | 260 + source/Target/StackFrame.cpp | 1920 ++ source/Target/StackFrameList.cpp | 853 + source/Target/StackID.cpp | 103 + source/Target/StopInfo.cpp | 1201 ++ source/Target/StructuredDataPlugin.cpp | 68 + source/Target/SystemRuntime.cpp | 58 + source/Target/Target.cpp | 4136 +++++ source/Target/TargetList.cpp | 630 + source/Target/Thread.cpp | 2211 +++ source/Target/ThreadCollection.cpp | 66 + source/Target/ThreadList.cpp | 760 + source/Target/ThreadPlan.cpp | 284 + source/Target/ThreadPlanBase.cpp | 212 + source/Target/ThreadPlanCallFunction.cpp | 514 + .../Target/ThreadPlanCallFunctionUsingABI.cpp | 75 + .../Target/ThreadPlanCallOnFunctionExit.cpp | 100 + .../Target/ThreadPlanCallUserExpression.cpp | 126 + source/Target/ThreadPlanPython.cpp | 206 + source/Target/ThreadPlanRunToAddress.cpp | 204 + source/Target/ThreadPlanShouldStopHere.cpp | 171 + source/Target/ThreadPlanStepInRange.cpp | 508 + source/Target/ThreadPlanStepInstruction.cpp | 253 + source/Target/ThreadPlanStepOut.cpp | 485 + .../Target/ThreadPlanStepOverBreakpoint.cpp | 173 + source/Target/ThreadPlanStepOverRange.cpp | 435 + source/Target/ThreadPlanStepRange.cpp | 478 + source/Target/ThreadPlanStepThrough.cpp | 254 + source/Target/ThreadPlanStepUntil.cpp | 341 + source/Target/ThreadPlanTracer.cpp | 231 + source/Target/ThreadSpec.cpp | 174 + source/Target/UnixSignals.cpp | 325 + source/Target/UnwindAssembly.cpp | 38 + source/Utility/ARM64_DWARF_Registers.h | 96 + source/Utility/ARM64_ehframe_Registers.h | 92 + source/Utility/ARM_DWARF_Registers.h | 208 + source/Utility/ARM_ehframe_Registers.h | 37 + source/Utility/Baton.cpp | 13 + source/Utility/CMakeLists.txt | 47 + source/Utility/Connection.cpp | 14 + source/Utility/ConstString.cpp | 340 + source/Utility/DataBufferHeap.cpp | 94 + source/Utility/DataBufferLLVM.cpp | 70 + source/Utility/DataEncoder.cpp | 285 + source/Utility/DataExtractor.cpp | 1245 ++ source/Utility/FastDemangle.cpp | 2397 +++ source/Utility/FileSpec.cpp | 966 + source/Utility/History.cpp | 24 + source/Utility/IOObject.cpp | 15 + source/Utility/JSON.cpp | 552 + source/Utility/LLDBAssert.cpp | 32 + source/Utility/Log.cpp | 323 + source/Utility/Logging.cpp | 74 + source/Utility/NameMatches.cpp | 35 + source/Utility/Range.cpp | 76 + source/Utility/RegularExpression.cpp | 198 + source/Utility/SelectHelper.cpp | 261 + source/Utility/SharingPtr.cpp | 135 + source/Utility/Status.cpp | 309 + source/Utility/Stream.cpp | 576 + source/Utility/StreamCallback.cpp | 23 + source/Utility/StreamGDBRemote.cpp | 46 + source/Utility/StreamString.cpp | 64 + source/Utility/StringExtractor.cpp | 427 + source/Utility/StringExtractorGDBRemote.cpp | 607 + source/Utility/StringExtractorGDBRemote.h | 204 + source/Utility/StringLexer.cpp | 88 + source/Utility/StringList.cpp | 268 + source/Utility/StructuredData.cpp | 286 + source/Utility/TaskPool.cpp | 98 + source/Utility/TildeExpressionResolver.cpp | 95 + source/Utility/Timer.cpp | 132 + source/Utility/UUID.cpp | 227 + source/Utility/UriParser.cpp | 73 + source/Utility/UserID.cpp | 21 + source/Utility/UuidCompatibility.h | 18 + source/Utility/VASprintf.cpp | 56 + source/Utility/VMRange.cpp | 69 + source/lldb.cpp | 83 + test/CMakeLists.txt | 123 + test/dotest.py | 7 + test/use_lldb_suite.py | 26 + third_party/Python/module/pexpect-2.4/ANSI.py | 370 + third_party/Python/module/pexpect-2.4/FSM.py | 370 + third_party/Python/module/pexpect-2.4/INSTALL | 31 + third_party/Python/module/pexpect-2.4/LICENSE | 21 + .../Python/module/pexpect-2.4/PKG-INFO | 10 + third_party/Python/module/pexpect-2.4/README | 45 + .../Python/module/pexpect-2.4/doc/clean.css | 103 + .../Python/module/pexpect-2.4/doc/email.png | Bin 0 -> 322 bytes .../module/pexpect-2.4/doc/examples.html | 135 + .../Python/module/pexpect-2.4/doc/index.html | 868 + .../pexpect-2.4/doc/index.template.html | 868 + .../Python/module/pexpect-2.4/examples/README | 72 + .../module/pexpect-2.4/examples/astat.py | 85 + .../module/pexpect-2.4/examples/bd_client.py | 40 + .../module/pexpect-2.4/examples/bd_serv.py | 339 + .../module/pexpect-2.4/examples/cgishell.cgi | 762 + .../module/pexpect-2.4/examples/chess.py | 132 + .../module/pexpect-2.4/examples/chess2.py | 135 + .../module/pexpect-2.4/examples/chess3.py | 139 + .../Python/module/pexpect-2.4/examples/df.py | 33 + .../pexpect-2.4/examples/fix_cvs_files.py | 98 + .../Python/module/pexpect-2.4/examples/ftp.py | 47 + .../module/pexpect-2.4/examples/hive.py | 472 + .../module/pexpect-2.4/examples/monitor.py | 222 + .../module/pexpect-2.4/examples/passmass.py | 95 + .../module/pexpect-2.4/examples/python.py | 21 + .../module/pexpect-2.4/examples/rippy.py | 1322 ++ .../module/pexpect-2.4/examples/script.py | 115 + .../pexpect-2.4/examples/ssh_session.py | 93 + .../module/pexpect-2.4/examples/ssh_tunnel.py | 76 + .../module/pexpect-2.4/examples/sshls.py | 57 + .../pexpect-2.4/examples/table_test.html | 106 + .../module/pexpect-2.4/examples/topip.py | 297 + .../module/pexpect-2.4/examples/uptime.py | 58 + .../Python/module/pexpect-2.4/fdpexpect.py | 98 + .../Python/module/pexpect-2.4/pexpect.py | 1894 ++ .../Python/module/pexpect-2.4/pxssh.py | 367 + .../Python/module/pexpect-2.4/screen.py | 349 + .../Python/module/pexpect-2.4/setup.py | 36 + .../Python/module/progress/progress.py | 184 + third_party/Python/module/six/LICENSE | 18 + third_party/Python/module/six/six.py | 887 + .../module/unittest2/unittest2/__init__.py | 78 + .../module/unittest2/unittest2/__main__.py | 10 + .../Python/module/unittest2/unittest2/case.py | 1174 ++ .../module/unittest2/unittest2/collector.py | 10 + .../unittest2/unittest2/compatibility.py | 67 + .../module/unittest2/unittest2/loader.py | 339 + .../Python/module/unittest2/unittest2/main.py | 258 + .../module/unittest2/unittest2/result.py | 196 + .../module/unittest2/unittest2/runner.py | 206 + .../module/unittest2/unittest2/signals.py | 63 + .../module/unittest2/unittest2/suite.py | 287 + .../unittest2/unittest2/test/__init__.py | 1 + .../module/unittest2/unittest2/test/dummy.py | 0 .../unittest2/unittest2/test/support.py | 189 + .../unittest2/test/test_assertions.py | 269 + .../unittest2/unittest2/test/test_break.py | 258 + .../unittest2/unittest2/test/test_case.py | 1245 ++ .../unittest2/test/test_discovery.py | 392 + .../unittest2/test/test_functiontestcase.py | 149 + .../unittest2/unittest2/test/test_loader.py | 1380 ++ .../unittest2/test/test_new_tests.py | 52 + .../unittest2/unittest2/test/test_program.py | 251 + .../unittest2/unittest2/test/test_result.py | 428 + .../unittest2/unittest2/test/test_runner.py | 136 + .../unittest2/unittest2/test/test_setups.py | 596 + .../unittest2/unittest2/test/test_skipping.py | 154 + .../unittest2/unittest2/test/test_suite.py | 363 + .../unittest2/test/test_unittest2_with.py | 150 + .../Python/module/unittest2/unittest2/util.py | 105 + tools/CMakeLists.txt | 11 + tools/argdumper/CMakeLists.txt | 10 + tools/argdumper/argdumper.cpp | 33 + tools/argdumper/argdumper.exports | 0 tools/compact-unwind/compact-unwind-dumper.c | 1515 ++ tools/darwin-debug/CMakeLists.txt | 3 + tools/darwin-debug/darwin-debug.cpp | 337 + tools/darwin-threads/examine-threads.c | 507 + tools/debugserver/CMakeLists.txt | 19 + tools/debugserver/debugnub-exports | 2 + .../debugserver.xcodeproj/project.pbxproj | 2090 +++ .../contents.xcworkspacedata | 7 + .../xcschemes/debugserver.xcscheme | 110 + .../resources/lldb-debugserver-Info.plist | 21 + .../scripts/diagnose-termination.d | 18 + .../debugserver/source/ARM_DWARF_Registers.h | 206 + .../source/ARM_ehframe_Registers.h | 34 + tools/debugserver/source/CMakeLists.txt | 139 + tools/debugserver/source/ChangeLog | 1515 ++ tools/debugserver/source/DNB.cpp | 1765 ++ tools/debugserver/source/DNB.h | 241 + tools/debugserver/source/DNBArch.cpp | 80 + tools/debugserver/source/DNBArch.h | 127 + tools/debugserver/source/DNBBreakpoint.cpp | 178 + tools/debugserver/source/DNBBreakpoint.h | 149 + tools/debugserver/source/DNBDataRef.cpp | 351 + tools/debugserver/source/DNBDataRef.h | 125 + tools/debugserver/source/DNBDefs.h | 373 + tools/debugserver/source/DNBError.cpp | 116 + tools/debugserver/source/DNBError.h | 98 + tools/debugserver/source/DNBLog.cpp | 287 + tools/debugserver/source/DNBLog.h | 153 + tools/debugserver/source/DNBRegisterInfo.cpp | 251 + tools/debugserver/source/DNBRegisterInfo.h | 30 + tools/debugserver/source/DNBRuntimeAction.h | 24 + .../source/DNBThreadResumeActions.cpp | 89 + .../source/DNBThreadResumeActions.h | 66 + tools/debugserver/source/DNBTimer.h | 145 + tools/debugserver/source/JSON.cpp | 588 + tools/debugserver/source/JSON.h | 303 + tools/debugserver/source/JSONGenerator.h | 319 + tools/debugserver/source/MacOSX/CFBundle.cpp | 80 + tools/debugserver/source/MacOSX/CFBundle.h | 38 + tools/debugserver/source/MacOSX/CFString.cpp | 163 + tools/debugserver/source/MacOSX/CFString.h | 43 + tools/debugserver/source/MacOSX/CFUtils.h | 78 + .../debugserver/source/MacOSX/CMakeLists.txt | 23 + .../source/MacOSX/DarwinLog/ActivityStore.cpp | 14 + .../source/MacOSX/DarwinLog/ActivityStore.h | 30 + .../MacOSX/DarwinLog/ActivityStreamSPI.h | 191 + .../source/MacOSX/DarwinLog/CMakeLists.txt | 15 + .../MacOSX/DarwinLog/DarwinLogCollector.cpp | 698 + .../MacOSX/DarwinLog/DarwinLogCollector.h | 114 + .../source/MacOSX/DarwinLog/DarwinLogEvent.h | 27 + .../MacOSX/DarwinLog/DarwinLogInterfaces.h | 25 + .../source/MacOSX/DarwinLog/DarwinLogTypes.h | 22 + .../source/MacOSX/DarwinLog/LogFilter.cpp | 12 + .../source/MacOSX/DarwinLog/LogFilter.h | 30 + .../MacOSX/DarwinLog/LogFilterChain.cpp | 42 + .../source/MacOSX/DarwinLog/LogFilterChain.h | 38 + .../MacOSX/DarwinLog/LogFilterExactMatch.cpp | 49 + .../MacOSX/DarwinLog/LogFilterExactMatch.h | 31 + .../MacOSX/DarwinLog/LogFilterRegex.cpp | 97 + .../source/MacOSX/DarwinLog/LogFilterRegex.h | 44 + .../source/MacOSX/DarwinLog/LogMessage.cpp | 14 + .../source/MacOSX/DarwinLog/LogMessage.h | 40 + .../MacOSX/DarwinLog/LogMessageOsLog.cpp | 68 + .../source/MacOSX/DarwinLog/LogMessageOsLog.h | 59 + tools/debugserver/source/MacOSX/Genealogy.cpp | 319 + tools/debugserver/source/MacOSX/Genealogy.h | 120 + .../debugserver/source/MacOSX/GenealogySPI.h | 95 + .../source/MacOSX/MachException.cpp | 503 + .../debugserver/source/MacOSX/MachException.h | 124 + tools/debugserver/source/MacOSX/MachProcess.h | 445 + .../debugserver/source/MacOSX/MachProcess.mm | 3833 ++++ tools/debugserver/source/MacOSX/MachTask.h | 117 + tools/debugserver/source/MacOSX/MachTask.mm | 1001 ++ .../debugserver/source/MacOSX/MachThread.cpp | 783 + tools/debugserver/source/MacOSX/MachThread.h | 170 + .../source/MacOSX/MachThreadList.cpp | 582 + .../source/MacOSX/MachThreadList.h | 97 + .../source/MacOSX/MachVMMemory.cpp | 570 + .../debugserver/source/MacOSX/MachVMMemory.h | 68 + .../source/MacOSX/MachVMRegion.cpp | 188 + .../debugserver/source/MacOSX/MachVMRegion.h | 73 + tools/debugserver/source/MacOSX/OsLogger.cpp | 68 + tools/debugserver/source/MacOSX/OsLogger.h | 20 + tools/debugserver/source/MacOSX/ThreadInfo.h | 26 + .../source/MacOSX/arm/DNBArchImpl.cpp | 2194 +++ .../source/MacOSX/arm/DNBArchImpl.h | 275 + .../source/MacOSX/arm64/DNBArchImplARM64.cpp | 2104 +++ .../source/MacOSX/arm64/DNBArchImplARM64.h | 249 + .../debugserver/source/MacOSX/dbgnub-mig.defs | 5 + .../source/MacOSX/i386/DNBArchImplI386.cpp | 2050 +++ .../source/MacOSX/i386/DNBArchImplI386.h | 231 + .../MacOSX/i386/MachRegisterStatesI386.h | 178 + .../source/MacOSX/ppc/DNBArchImpl.cpp | 492 + .../source/MacOSX/ppc/DNBArchImpl.h | 160 + .../debugserver/source/MacOSX/stack_logging.h | 158 + .../MacOSX/x86_64/DNBArchImplX86_64.cpp | 2328 +++ .../source/MacOSX/x86_64/DNBArchImplX86_64.h | 234 + .../MacOSX/x86_64/MachRegisterStatesX86_64.h | 208 + tools/debugserver/source/PThreadCondition.h | 35 + tools/debugserver/source/PThreadEvent.cpp | 200 + tools/debugserver/source/PThreadEvent.h | 64 + tools/debugserver/source/PThreadMutex.cpp | 71 + tools/debugserver/source/PThreadMutex.h | 120 + tools/debugserver/source/PseudoTerminal.cpp | 196 + tools/debugserver/source/PseudoTerminal.h | 87 + tools/debugserver/source/RNBContext.cpp | 278 + tools/debugserver/source/RNBContext.h | 163 + tools/debugserver/source/RNBDefs.h | 99 + tools/debugserver/source/RNBRemote.cpp | 6287 +++++++ tools/debugserver/source/RNBRemote.h | 433 + tools/debugserver/source/RNBServices.cpp | 235 + tools/debugserver/source/RNBServices.h | 29 + tools/debugserver/source/RNBSocket.cpp | 391 + tools/debugserver/source/RNBSocket.h | 79 + .../debugserver/source/StdStringExtractor.cpp | 405 + tools/debugserver/source/StdStringExtractor.h | 125 + tools/debugserver/source/SysSignal.cpp | 95 + tools/debugserver/source/SysSignal.h | 22 + tools/debugserver/source/TTYState.cpp | 94 + tools/debugserver/source/TTYState.h | 59 + ...m.apple.debugserver.applist.internal.plist | 16 + .../com.apple.debugserver.applist.plist | 19 + .../com.apple.debugserver.internal.plist | 15 + .../source/com.apple.debugserver.plist | 18 + .../source/com.apple.debugserver.posix.plist | 18 + .../source/debugserver-entitlements.plist | 28 + .../debugserver-macosx-entitlements.plist | 8 + tools/debugserver/source/debugserver.cpp | 1680 ++ tools/debugserver/source/libdebugserver.cpp | 383 + tools/debugserver/source/libdebugserver.h | 15 + tools/driver/CMakeLists.txt | 37 + tools/driver/Driver.cpp | 1259 ++ tools/driver/Driver.h | 125 + tools/driver/Platform.cpp | 60 + tools/driver/Platform.h | 89 + tools/driver/lldb-Info.plist | 21 + tools/install-headers/Makefile | 23 + tools/intel-mpx/CMakeLists.txt | 15 + tools/intel-mpx/IntelMPXTablePlugin.cpp | 427 + tools/intel-mpx/test/Makefile | 7 + tools/intel-mpx/test/README.txt | 6 + tools/intel-mpx/test/TestMPXTable.py | 168 + tools/intel-mpx/test/main.cpp | 48 + tools/lldb-mi/CMakeLists.txt | 95 + tools/lldb-mi/MICmdArgContext.cpp | 232 + tools/lldb-mi/MICmdArgContext.h | 44 + tools/lldb-mi/MICmdArgSet.cpp | 401 + tools/lldb-mi/MICmdArgSet.h | 112 + tools/lldb-mi/MICmdArgValBase.cpp | 143 + tools/lldb-mi/MICmdArgValBase.h | 122 + tools/lldb-mi/MICmdArgValConsume.cpp | 94 + tools/lldb-mi/MICmdArgValConsume.h | 54 + tools/lldb-mi/MICmdArgValFile.cpp | 189 + tools/lldb-mi/MICmdArgValFile.h | 48 + tools/lldb-mi/MICmdArgValListBase.cpp | 217 + tools/lldb-mi/MICmdArgValListBase.h | 103 + tools/lldb-mi/MICmdArgValListOfN.cpp | 175 + tools/lldb-mi/MICmdArgValListOfN.h | 94 + tools/lldb-mi/MICmdArgValNumber.cpp | 164 + tools/lldb-mi/MICmdArgValNumber.h | 71 + tools/lldb-mi/MICmdArgValOptionLong.cpp | 306 + tools/lldb-mi/MICmdArgValOptionLong.h | 106 + tools/lldb-mi/MICmdArgValOptionShort.cpp | 129 + tools/lldb-mi/MICmdArgValOptionShort.h | 60 + tools/lldb-mi/MICmdArgValPrintValues.cpp | 133 + tools/lldb-mi/MICmdArgValPrintValues.h | 57 + tools/lldb-mi/MICmdArgValString.cpp | 398 + tools/lldb-mi/MICmdArgValString.h | 83 + tools/lldb-mi/MICmdArgValThreadGrp.cpp | 152 + tools/lldb-mi/MICmdArgValThreadGrp.h | 54 + tools/lldb-mi/MICmdBase.cpp | 292 + tools/lldb-mi/MICmdBase.h | 188 + tools/lldb-mi/MICmdCmd.cpp | 172 + tools/lldb-mi/MICmdCmd.h | 91 + tools/lldb-mi/MICmdCmdBreak.cpp | 1064 ++ tools/lldb-mi/MICmdCmdBreak.h | 263 + tools/lldb-mi/MICmdCmdData.cpp | 1821 ++ tools/lldb-mi/MICmdCmdData.h | 382 + tools/lldb-mi/MICmdCmdEnviro.cpp | 152 + tools/lldb-mi/MICmdCmdEnviro.h | 58 + tools/lldb-mi/MICmdCmdExec.cpp | 1247 ++ tools/lldb-mi/MICmdCmdExec.h | 336 + tools/lldb-mi/MICmdCmdFile.cpp | 214 + tools/lldb-mi/MICmdCmdFile.h | 67 + tools/lldb-mi/MICmdCmdGdbInfo.cpp | 234 + tools/lldb-mi/MICmdCmdGdbInfo.h | 88 + tools/lldb-mi/MICmdCmdGdbSet.cpp | 455 + tools/lldb-mi/MICmdCmdGdbSet.h | 101 + tools/lldb-mi/MICmdCmdGdbShow.cpp | 371 + tools/lldb-mi/MICmdCmdGdbShow.h | 101 + tools/lldb-mi/MICmdCmdGdbThread.cpp | 95 + tools/lldb-mi/MICmdCmdGdbThread.h | 51 + tools/lldb-mi/MICmdCmdMiscellanous.cpp | 617 + tools/lldb-mi/MICmdCmdMiscellanous.h | 157 + tools/lldb-mi/MICmdCmdStack.cpp | 1114 ++ tools/lldb-mi/MICmdCmdStack.h | 257 + tools/lldb-mi/MICmdCmdSupportInfo.cpp | 124 + tools/lldb-mi/MICmdCmdSupportInfo.h | 59 + tools/lldb-mi/MICmdCmdSupportList.cpp | 102 + tools/lldb-mi/MICmdCmdSupportList.h | 52 + tools/lldb-mi/MICmdCmdSymbol.cpp | 268 + tools/lldb-mi/MICmdCmdSymbol.h | 60 + tools/lldb-mi/MICmdCmdTarget.cpp | 489 + tools/lldb-mi/MICmdCmdTarget.h | 118 + tools/lldb-mi/MICmdCmdThread.cpp | 218 + tools/lldb-mi/MICmdCmdThread.h | 70 + tools/lldb-mi/MICmdCmdTrace.cpp | 94 + tools/lldb-mi/MICmdCmdTrace.h | 51 + tools/lldb-mi/MICmdCmdVar.cpp | 1542 ++ tools/lldb-mi/MICmdCmdVar.h | 349 + tools/lldb-mi/MICmdCommands.cpp | 137 + tools/lldb-mi/MICmdCommands.h | 20 + tools/lldb-mi/MICmdData.cpp | 11 + tools/lldb-mi/MICmdData.h | 59 + tools/lldb-mi/MICmdFactory.cpp | 219 + tools/lldb-mi/MICmdFactory.h | 85 + tools/lldb-mi/MICmdInterpreter.cpp | 302 + tools/lldb-mi/MICmdInterpreter.h | 63 + tools/lldb-mi/MICmdInvoker.cpp | 334 + tools/lldb-mi/MICmdInvoker.h | 104 + tools/lldb-mi/MICmdMgr.cpp | 258 + tools/lldb-mi/MICmdMgr.h | 70 + .../lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp | 93 + tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h | 73 + tools/lldb-mi/MICmnBase.cpp | 132 + tools/lldb-mi/MICmnBase.h | 47 + tools/lldb-mi/MICmnConfig.h | 20 + tools/lldb-mi/MICmnLLDBBroadcaster.cpp | 73 + tools/lldb-mi/MICmnLLDBBroadcaster.h | 45 + tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp | 887 + tools/lldb-mi/MICmnLLDBDebugSessionInfo.h | 295 + .../MICmnLLDBDebugSessionInfoVarObj.cpp | 607 + .../lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h | 140 + tools/lldb-mi/MICmnLLDBDebugger.cpp | 937 + tools/lldb-mi/MICmnLLDBDebugger.h | 135 + .../lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp | 1914 ++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h | 99 + tools/lldb-mi/MICmnLLDBProxySBValue.cpp | 138 + tools/lldb-mi/MICmnLLDBProxySBValue.h | 35 + tools/lldb-mi/MICmnLLDBUtilSBValue.cpp | 518 + tools/lldb-mi/MICmnLLDBUtilSBValue.h | 78 + tools/lldb-mi/MICmnLog.cpp | 349 + tools/lldb-mi/MICmnLog.h | 139 + tools/lldb-mi/MICmnLogMediumFile.cpp | 409 + tools/lldb-mi/MICmnLogMediumFile.h | 85 + tools/lldb-mi/MICmnMIOutOfBandRecord.cpp | 209 + tools/lldb-mi/MICmnMIOutOfBandRecord.h | 94 + tools/lldb-mi/MICmnMIResultRecord.cpp | 141 + tools/lldb-mi/MICmnMIResultRecord.h | 80 + tools/lldb-mi/MICmnMIValue.cpp | 47 + tools/lldb-mi/MICmnMIValue.h | 51 + tools/lldb-mi/MICmnMIValueConst.cpp | 82 + tools/lldb-mi/MICmnMIValueConst.h | 60 + tools/lldb-mi/MICmnMIValueList.cpp | 188 + tools/lldb-mi/MICmnMIValueList.h | 56 + tools/lldb-mi/MICmnMIValueResult.cpp | 124 + tools/lldb-mi/MICmnMIValueResult.h | 67 + tools/lldb-mi/MICmnMIValueTuple.cpp | 206 + tools/lldb-mi/MICmnMIValueTuple.h | 64 + tools/lldb-mi/MICmnResources.cpp | 620 + tools/lldb-mi/MICmnResources.h | 336 + tools/lldb-mi/MICmnStreamStderr.cpp | 261 + tools/lldb-mi/MICmnStreamStderr.h | 62 + tools/lldb-mi/MICmnStreamStdin.cpp | 228 + tools/lldb-mi/MICmnStreamStdin.h | 61 + tools/lldb-mi/MICmnStreamStdout.cpp | 242 + tools/lldb-mi/MICmnStreamStdout.h | 63 + tools/lldb-mi/MICmnThreadMgrStd.cpp | 152 + tools/lldb-mi/MICmnThreadMgrStd.h | 125 + tools/lldb-mi/MIDataTypes.h | 64 + tools/lldb-mi/MIDriver.cpp | 1366 ++ tools/lldb-mi/MIDriver.h | 181 + tools/lldb-mi/MIDriverBase.cpp | 191 + tools/lldb-mi/MIDriverBase.h | 68 + tools/lldb-mi/MIDriverMain.cpp | 201 + tools/lldb-mi/MIDriverMgr.cpp | 750 + tools/lldb-mi/MIDriverMgr.h | 129 + tools/lldb-mi/MIExtensions.txt | 104 + tools/lldb-mi/MIReadMe.txt | 37 + tools/lldb-mi/MIUtilDateTimeStd.cpp | 90 + tools/lldb-mi/MIUtilDateTimeStd.h | 41 + tools/lldb-mi/MIUtilDebug.cpp | 119 + tools/lldb-mi/MIUtilDebug.h | 81 + tools/lldb-mi/MIUtilFileStd.cpp | 291 + tools/lldb-mi/MIUtilFileStd.h | 49 + tools/lldb-mi/MIUtilMapIdToVariant.cpp | 110 + tools/lldb-mi/MIUtilMapIdToVariant.h | 132 + tools/lldb-mi/MIUtilSingletonBase.h | 53 + tools/lldb-mi/MIUtilSingletonHelper.h | 82 + tools/lldb-mi/MIUtilString.cpp | 961 + tools/lldb-mi/MIUtilString.h | 93 + tools/lldb-mi/MIUtilThreadBaseStd.cpp | 327 + tools/lldb-mi/MIUtilThreadBaseStd.h | 141 + tools/lldb-mi/MIUtilVariant.cpp | 376 + tools/lldb-mi/MIUtilVariant.h | 264 + tools/lldb-mi/Platform.h | 88 + tools/lldb-mi/lldb-Info.plist | 21 + tools/lldb-mi/lldb-mi.exports | 0 tools/lldb-perf/README | 295 + tools/lldb-perf/common/clang/build-clang.sh | 33 + .../common/clang/lldb_perf_clang.cpp | 442 + tools/lldb-perf/common/clang/main.cpp | 20 + .../common/stepping/lldb-perf-stepping.cpp | 287 + .../common/stepping/stepping-testcase.cpp | 35 + .../darwin/formatters/fmts_tester.mm | 82 + .../darwin/formatters/formatters.cpp | 268 + tools/lldb-perf/darwin/sketch/foobar.sketch2 | Bin 0 -> 10027 bytes tools/lldb-perf/darwin/sketch/sketch.cpp | 330 + tools/lldb-perf/lib/Gauge.cpp | 50 + tools/lldb-perf/lib/Gauge.h | 51 + tools/lldb-perf/lib/Measurement.h | 158 + tools/lldb-perf/lib/MemoryGauge.cpp | 133 + tools/lldb-perf/lib/MemoryGauge.h | 92 + tools/lldb-perf/lib/Metric.cpp | 60 + tools/lldb-perf/lib/Metric.h | 58 + tools/lldb-perf/lib/Results.cpp | 237 + tools/lldb-perf/lib/Results.h | 205 + tools/lldb-perf/lib/TestCase.cpp | 308 + tools/lldb-perf/lib/TestCase.h | 145 + tools/lldb-perf/lib/Timer.cpp | 47 + tools/lldb-perf/lib/Timer.h | 49 + tools/lldb-perf/lib/Xcode.cpp | 137 + tools/lldb-perf/lib/Xcode.h | 58 + .../lldbperf.xcodeproj/project.pbxproj | 1224 ++ tools/lldb-server/Acceptor.cpp | 136 + tools/lldb-server/Acceptor.h | 61 + tools/lldb-server/CMakeLists.txt | 92 + .../Darwin/resources/lldb-server-Info.plist | 21 + .../resources/lldb-server-entitlements.plist | 28 + .../lldb-server-macos-entitlements.plist | 8 + .../Darwin/resources/lldb-server-mig.defs | 5 + tools/lldb-server/LLDBServerUtilities.cpp | 65 + tools/lldb-server/LLDBServerUtilities.h | 24 + tools/lldb-server/lldb-gdbserver.cpp | 516 + tools/lldb-server/lldb-platform.cpp | 380 + tools/lldb-server/lldb-server.cpp | 73 + tools/lldb-server/lldb-server.exports | 0 unittests/Breakpoint/BreakpointIDTest.cpp | 30 + unittests/Breakpoint/CMakeLists.txt | 9 + unittests/CMakeLists.txt | 83 + unittests/Core/ArchSpecTest.cpp | 155 + unittests/Core/BroadcasterTest.cpp | 75 + unittests/Core/CMakeLists.txt | 15 + unittests/Core/DataExtractorTest.cpp | 51 + unittests/Core/ListenerTest.cpp | 114 + unittests/Core/ScalarTest.cpp | 134 + unittests/Core/StateTest.cpp | 21 + unittests/Core/StreamCallbackTest.cpp | 28 + unittests/Editline/CMakeLists.txt | 8 + unittests/Editline/EditlineTest.cpp | 313 + unittests/Expression/CMakeLists.txt | 7 + unittests/Expression/GoParserTest.cpp | 273 + unittests/Host/CMakeLists.txt | 23 + unittests/Host/FileSpecTest.cpp | 310 + unittests/Host/FileSystemTest.cpp | 32 + unittests/Host/HostTest.cpp | 22 + unittests/Host/MainLoopTest.cpp | 120 + unittests/Host/SocketAddressTest.cpp | 91 + unittests/Host/SocketTest.cpp | 233 + unittests/Host/SymbolsTest.cpp | 32 + unittests/Host/linux/HostTest.cpp | 48 + unittests/Host/linux/SupportTest.cpp | 26 + unittests/Interpreter/CMakeLists.txt | 12 + unittests/Interpreter/TestArgs.cpp | 351 + unittests/Interpreter/TestCompletion.cpp | 306 + unittests/Language/CMakeLists.txt | 1 + unittests/Language/CPlusPlus/CMakeLists.txt | 6 + .../CPlusPlus/CPlusPlusLanguageTest.cpp | 163 + unittests/ObjectFile/CMakeLists.txt | 1 + unittests/ObjectFile/ELF/CMakeLists.txt | 18 + .../Inputs/sections-resolve-consistently.yaml | 50 + unittests/ObjectFile/ELF/TestELFHeader.cpp | 62 + .../ObjectFile/ELF/TestObjectFileELF.cpp | 97 + unittests/Platform/CMakeLists.txt | 8 + unittests/Platform/PlatformDarwinTest.cpp | 56 + unittests/Process/CMakeLists.txt | 5 + unittests/Process/Linux/CMakeLists.txt | 8 + .../Process/Linux/ProcessorTraceTest.cpp | 150 + unittests/Process/gdb-remote/CMakeLists.txt | 17 + .../gdb-remote/GDBRemoteClientBaseTest.cpp | 341 + .../GDBRemoteCommunicationClientTest.cpp | 508 + .../Process/gdb-remote/GDBRemoteTestUtils.cpp | 63 + .../Process/gdb-remote/GDBRemoteTestUtils.h | 52 + unittests/Process/minidump/CMakeLists.txt | 22 + .../minidump/Inputs/fizzbuzz_no_heap.dmp | Bin 0 -> 6297 bytes .../minidump/Inputs/fizzbuzz_wow64.dmp | Bin 0 -> 9280561 bytes .../Process/minidump/Inputs/linux-i386.dmp | Bin 0 -> 32976 bytes .../Process/minidump/Inputs/linux-x86_64.cpp | 28 + .../Process/minidump/Inputs/linux-x86_64.dmp | Bin 0 -> 38320 bytes .../Inputs/linux-x86_64_not_crashed.dmp | Bin 0 -> 63744 bytes .../Process/minidump/MinidumpParserTest.cpp | 445 + unittests/ScriptInterpreter/CMakeLists.txt | 3 + .../ScriptInterpreter/Python/CMakeLists.txt | 13 + .../Python/PythonDataObjectsTests.cpp | 600 + .../Python/PythonExceptionStateTests.cpp | 165 + .../Python/PythonTestSuite.cpp | 39 + .../Python/PythonTestSuite.h | 22 + unittests/Signals/CMakeLists.txt | 6 + unittests/Signals/UnixSignalsTest.cpp | 140 + unittests/Symbol/CMakeLists.txt | 17 + .../Symbol/Inputs/basic-call-frame-info.yaml | 138 + unittests/Symbol/TestClangASTContext.cpp | 378 + unittests/Symbol/TestDWARFCallFrameInfo.cpp | 142 + unittests/Symbol/TestType.cpp | 51 + unittests/SymbolFile/CMakeLists.txt | 4 + unittests/SymbolFile/DWARF/CMakeLists.txt | 20 + .../SymbolFile/DWARF/Inputs/test-dwarf.cpp | 6 + .../SymbolFile/DWARF/Inputs/test-dwarf.exe | Bin 0 -> 6144 bytes .../SymbolFile/DWARF/SymbolFileDWARFTests.cpp | 76 + unittests/SymbolFile/PDB/CMakeLists.txt | 23 + .../SymbolFile/PDB/Inputs/test-pdb-alt.cpp | 7 + .../SymbolFile/PDB/Inputs/test-pdb-nested.h | 6 + .../SymbolFile/PDB/Inputs/test-pdb-types.cpp | 72 + .../SymbolFile/PDB/Inputs/test-pdb-types.exe | Bin 0 -> 7168 bytes .../SymbolFile/PDB/Inputs/test-pdb-types.pdb | Bin 0 -> 143360 bytes unittests/SymbolFile/PDB/Inputs/test-pdb.cpp | 9 + unittests/SymbolFile/PDB/Inputs/test-pdb.exe | Bin 0 -> 7168 bytes unittests/SymbolFile/PDB/Inputs/test-pdb.h | 10 + unittests/SymbolFile/PDB/Inputs/test-pdb.pdb | Bin 0 -> 110592 bytes .../SymbolFile/PDB/SymbolFilePDBTests.cpp | 567 + unittests/Target/CMakeLists.txt | 16 + unittests/Target/Inputs/TestModule.c | 9 + unittests/Target/Inputs/TestModule.so | Bin 0 -> 5602 bytes unittests/Target/MemoryRegionInfoTest.cpp | 20 + unittests/Target/ModuleCacheTest.cpp | 165 + unittests/UnwindAssembly/CMakeLists.txt | 5 + .../InstEmulation/CMakeLists.txt | 15 + .../InstEmulation/TestArm64InstEmulation.cpp | 672 + unittests/UnwindAssembly/x86/CMakeLists.txt | 10 + .../x86/Testx86AssemblyInspectionEngine.cpp | 2442 +++ unittests/Utility/CMakeLists.txt | 26 + unittests/Utility/ConstStringTest.cpp | 18 + unittests/Utility/Helpers/CMakeLists.txt | 11 + .../Helpers/MockTildeExpressionResolver.cpp | 80 + .../Helpers/MockTildeExpressionResolver.h | 37 + unittests/Utility/Helpers/TestUtilities.cpp | 22 + unittests/Utility/Helpers/TestUtilities.h | 20 + .../Utility/Inputs/StructuredData-basic.json | 1 + unittests/Utility/LogTest.cpp | 280 + unittests/Utility/NameMatchesTest.cpp | 58 + unittests/Utility/StatusTest.cpp | 53 + unittests/Utility/StringExtractorTest.cpp | 698 + unittests/Utility/StructuredDataTest.cpp | 48 + unittests/Utility/TaskPoolTest.cpp | 43 + .../Utility/TildeExpressionResolverTest.cpp | 36 + unittests/Utility/TimeoutTest.cpp | 30 + unittests/Utility/TimerTest.cpp | 72 + unittests/Utility/UriParserTest.cpp | 153 + unittests/Utility/VASprintfTest.cpp | 59 + unittests/debugserver/CMakeLists.txt | 19 + unittests/debugserver/RNBSocketTest.cpp | 160 + .../debugserver/debugserver_LogCallback.cpp | 20 + unittests/gtest_common.h | 17 + unittests/tools/CMakeLists.txt | 3 + unittests/tools/lldb-server/CMakeLists.txt | 13 + .../lldb-server/inferior/thread_inferior.cpp | 41 + .../tools/lldb-server/tests/CMakeLists.txt | 15 + .../lldb-server/tests/MessageObjects.cpp | 207 + .../tools/lldb-server/tests/MessageObjects.h | 102 + .../tools/lldb-server/tests/TestClient.cpp | 286 + .../tools/lldb-server/tests/TestClient.h | 61 + .../tests/ThreadIdsInJstopinfoTest.cpp | 58 + use_lldb_suite_root.py | 25 + utils/git-svn/convert.py | 71 + utils/lui/Readme | 36 + utils/lui/breakwin.py | 94 + utils/lui/commandwin.py | 131 + utils/lui/cui.py | 339 + utils/lui/debuggerdriver.py | 143 + utils/lui/eventwin.py | 27 + utils/lui/lldbutil.py | 1039 ++ utils/lui/lui.py | 150 + utils/lui/sandbox.py | 75 + utils/lui/sourcewin.py | 239 + utils/lui/statuswin.py | 42 + utils/misc/grep-svn-log.py | 96 + utils/sync-source/README.txt | 293 + utils/sync-source/lib/transfer/__init__.py | 0 utils/sync-source/lib/transfer/protocol.py | 8 + utils/sync-source/lib/transfer/rsync.py | 61 + .../sync-source/lib/transfer/transfer_spec.py | 12 + utils/sync-source/pylintrc | 2 + utils/sync-source/syncsource.py | 271 + utils/test/README-disasm | 406 + utils/test/README-lldb-disasm | 94 + utils/test/README-run-until-faulted | 18 + utils/test/disasm.py | 236 + utils/test/lldb-disasm.py | 292 + utils/test/llvm-mc-shell.py | 114 + utils/test/main.c | 13 + utils/test/ras.py | 180 + utils/test/run-dis.py | 142 + utils/test/run-until-faulted.py | 130 + utils/vim-lldb/README | 59 + utils/vim-lldb/doc/lldb.txt | 115 + utils/vim-lldb/plugin/lldb.vim | 151 + utils/vim-lldb/python-vim-lldb/import_lldb.py | 71 + .../python-vim-lldb/lldb_controller.py | 413 + utils/vim-lldb/python-vim-lldb/plugin.py | 16 + utils/vim-lldb/python-vim-lldb/vim_panes.py | 669 + utils/vim-lldb/python-vim-lldb/vim_signs.py | 81 + utils/vim-lldb/python-vim-lldb/vim_ui.py | 255 + 4716 files changed, 903399 insertions(+) create mode 100644 .arcconfig create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CODE_OWNERS.txt create mode 100644 INSTALL.txt create mode 100644 LICENSE.TXT create mode 100644 cmake/LLDBDependencies.cmake create mode 100644 cmake/XcodeHeaderGenerator/CMakeLists.txt create mode 100644 cmake/modules/AddLLDB.cmake create mode 100644 cmake/modules/EmbedAppleVersion.cmake create mode 100644 cmake/modules/LLDBConfig.cmake create mode 100644 cmake/modules/LLDBGenerateConfig.cmake create mode 100644 cmake/modules/LLDBStandalone.cmake create mode 100644 docs/CMakeLists.txt create mode 100644 docs/building-with-debug-llvm.txt create mode 100644 docs/code-signing.txt create mode 100644 docs/doxygen.cfg.in create mode 100644 docs/doxygen.footer create mode 100644 docs/doxygen.header create mode 100644 docs/doxygen.intro create mode 100644 docs/lldb-for-gdb-users.txt create mode 100644 docs/lldb-gdb-remote.txt create mode 100644 docs/lldb.1 create mode 100644 docs/structured_data/DarwinLog.md create mode 100644 docs/structured_data/StructuredDataPlugins.md create mode 100644 docs/testsuite/2010-10-19-14_10_49.059609/TestSettings.SettingsCommandTestCase.test_set_output_path.log create mode 100644 docs/testsuite/a-detailed-walkthrough.txt create mode 100644 docs/testsuite/best-practices.txt create mode 100644 examples/customization/bin-utils/.lldbinit create mode 100644 examples/customization/bin-utils/README create mode 100644 examples/customization/bin-utils/binutils.py create mode 100644 examples/customization/import-python/README create mode 100644 examples/customization/import-python/importcmd.py create mode 100644 examples/customization/pwd-cd-and-system/.lldbinit create mode 100644 examples/customization/pwd-cd-and-system/README create mode 100644 examples/customization/pwd-cd-and-system/utils.py create mode 100644 examples/darwin/heap_find/heap.py create mode 100644 examples/darwin/heap_find/heap/Makefile create mode 100644 examples/darwin/heap_find/heap/heap_find.cpp create mode 100644 examples/functions/Makefile create mode 100644 examples/functions/main.cpp create mode 100644 examples/interposing/darwin/fd_interposing/FDInterposing.cpp create mode 100644 examples/interposing/darwin/fd_interposing/Makefile create mode 100644 examples/lookup/Makefile create mode 100644 examples/lookup/main.cpp create mode 100644 examples/plugins/commands/fooplugin.cpp create mode 100644 examples/python/cmdtemplate.py create mode 100755 examples/python/crashlog.py create mode 100755 examples/python/delta.py create mode 100644 examples/python/diagnose_nsstring.py create mode 100644 examples/python/diagnose_unwind.py create mode 100755 examples/python/dict_utils.py create mode 100755 examples/python/disasm-stress-test.py create mode 100755 examples/python/disasm.py create mode 100644 examples/python/disassembly_mode.py create mode 100755 examples/python/file_extract.py create mode 100755 examples/python/gdb_disassemble.py create mode 100755 examples/python/gdbremote.py create mode 100755 examples/python/globals.py create mode 100644 examples/python/jump.py create mode 100644 examples/python/lldb_module_utils.py create mode 100644 examples/python/lldbtk.py create mode 100755 examples/python/mach_o.py create mode 100755 examples/python/memory.py create mode 100644 examples/python/operating_system.py create mode 100755 examples/python/performance.py create mode 100755 examples/python/process_events.py create mode 100644 examples/python/pytracer.py create mode 100755 examples/python/sbvalue.py create mode 100644 examples/python/scripted_step.py create mode 100644 examples/python/shadow.py create mode 100644 examples/python/sources.py create mode 100755 examples/python/stacks.py create mode 100755 examples/python/symbolication.py create mode 100755 examples/python/types.py create mode 100644 examples/python/x86_64_linux_target_definition.py create mode 100644 examples/python/x86_64_qemu_target_definition.py create mode 100644 examples/python/x86_64_target_definition.py create mode 100644 examples/scripting/dictionary.c create mode 100755 examples/scripting/tree_utils.py create mode 100644 examples/summaries/cocoa/CFArray.py create mode 100644 examples/summaries/cocoa/CFBag.py create mode 100644 examples/summaries/cocoa/CFBinaryHeap.py create mode 100644 examples/summaries/cocoa/CFBitVector.py create mode 100644 examples/summaries/cocoa/CFDictionary.py create mode 100644 examples/summaries/cocoa/CFString.py create mode 100644 examples/summaries/cocoa/Class.py create mode 100644 examples/summaries/cocoa/Logger.py create mode 100644 examples/summaries/cocoa/NSBundle.py create mode 100644 examples/summaries/cocoa/NSData.py create mode 100644 examples/summaries/cocoa/NSDate.py create mode 100644 examples/summaries/cocoa/NSException.py create mode 100644 examples/summaries/cocoa/NSIndexSet.py create mode 100644 examples/summaries/cocoa/NSMachPort.py create mode 100644 examples/summaries/cocoa/NSNotification.py create mode 100644 examples/summaries/cocoa/NSNumber.py create mode 100644 examples/summaries/cocoa/NSSet.py create mode 100644 examples/summaries/cocoa/NSURL.py create mode 100644 examples/summaries/cocoa/Selector.py create mode 100644 examples/summaries/cocoa/attrib_fromdict.py create mode 100644 examples/summaries/cocoa/cache.py create mode 100644 examples/summaries/cocoa/metrics.py create mode 100644 examples/summaries/cocoa/objc_runtime.py create mode 100644 examples/summaries/essentials create mode 100644 examples/summaries/lldb create mode 100644 examples/summaries/objc.py create mode 100644 examples/summaries/pysummary.py create mode 100644 examples/summaries/sp_cp.py create mode 100644 examples/summaries/synth.py create mode 100644 examples/summaries/unicode_strings.py create mode 100644 examples/synthetic/bitfield/example.py create mode 100644 examples/synthetic/bitfield/program.cpp create mode 100644 examples/synthetic/gnu_libstdcpp.py create mode 100644 examples/synthetic/libcxx.py create mode 100644 examples/synthetic/unordered_multi.py create mode 100644 examples/test/.lldb-loggings create mode 100644 examples/test/.lldb-pre-post-flight create mode 100644 examples/test/.lldb-pre-post-flight.bad create mode 100644 examples/test/.lldbtest-config create mode 100644 examples/test/.lldbtest-config2 create mode 100644 examples/test/lldbtest-stderr create mode 100644 examples/test/lldbtest-stdout create mode 100644 examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt create mode 100644 examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt create mode 100644 examples/test/usage-config create mode 100644 examples/test/usage-lldb-loggings create mode 100644 examples/test/usage-pre-post-flight create mode 100644 include/lldb/API/LLDB.h create mode 100644 include/lldb/API/SBAddress.h create mode 100644 include/lldb/API/SBAttachInfo.h create mode 100644 include/lldb/API/SBBlock.h create mode 100644 include/lldb/API/SBBreakpoint.h create mode 100644 include/lldb/API/SBBreakpointLocation.h create mode 100644 include/lldb/API/SBBroadcaster.h create mode 100644 include/lldb/API/SBCommandInterpreter.h create mode 100644 include/lldb/API/SBCommandReturnObject.h create mode 100644 include/lldb/API/SBCommunication.h create mode 100644 include/lldb/API/SBCompileUnit.h create mode 100644 include/lldb/API/SBData.h create mode 100644 include/lldb/API/SBDebugger.h create mode 100644 include/lldb/API/SBDeclaration.h create mode 100644 include/lldb/API/SBDefines.h create mode 100644 include/lldb/API/SBError.h create mode 100644 include/lldb/API/SBEvent.h create mode 100644 include/lldb/API/SBExecutionContext.h create mode 100644 include/lldb/API/SBExpressionOptions.h create mode 100644 include/lldb/API/SBFileSpec.h create mode 100644 include/lldb/API/SBFileSpecList.h create mode 100644 include/lldb/API/SBFrame.h create mode 100644 include/lldb/API/SBFunction.h create mode 100644 include/lldb/API/SBHostOS.h create mode 100644 include/lldb/API/SBInstruction.h create mode 100644 include/lldb/API/SBInstructionList.h create mode 100644 include/lldb/API/SBLanguageRuntime.h create mode 100644 include/lldb/API/SBLaunchInfo.h create mode 100644 include/lldb/API/SBLineEntry.h create mode 100644 include/lldb/API/SBListener.h create mode 100644 include/lldb/API/SBMemoryRegionInfo.h create mode 100644 include/lldb/API/SBMemoryRegionInfoList.h create mode 100644 include/lldb/API/SBModule.h create mode 100644 include/lldb/API/SBModuleSpec.h create mode 100644 include/lldb/API/SBPlatform.h create mode 100644 include/lldb/API/SBProcess.h create mode 100644 include/lldb/API/SBQueue.h create mode 100644 include/lldb/API/SBQueueItem.h create mode 100644 include/lldb/API/SBSection.h create mode 100644 include/lldb/API/SBSourceManager.h create mode 100644 include/lldb/API/SBStream.h create mode 100644 include/lldb/API/SBStringList.h create mode 100644 include/lldb/API/SBStructuredData.h create mode 100644 include/lldb/API/SBSymbol.h create mode 100644 include/lldb/API/SBSymbolContext.h create mode 100644 include/lldb/API/SBSymbolContextList.h create mode 100644 include/lldb/API/SBTarget.h create mode 100644 include/lldb/API/SBThread.h create mode 100644 include/lldb/API/SBThreadCollection.h create mode 100644 include/lldb/API/SBThreadPlan.h create mode 100644 include/lldb/API/SBTrace.h create mode 100644 include/lldb/API/SBTraceOptions.h create mode 100644 include/lldb/API/SBType.h create mode 100644 include/lldb/API/SBTypeCategory.h create mode 100644 include/lldb/API/SBTypeEnumMember.h create mode 100644 include/lldb/API/SBTypeFilter.h create mode 100644 include/lldb/API/SBTypeFormat.h create mode 100644 include/lldb/API/SBTypeNameSpecifier.h create mode 100644 include/lldb/API/SBTypeSummary.h create mode 100644 include/lldb/API/SBTypeSynthetic.h create mode 100644 include/lldb/API/SBUnixSignals.h create mode 100644 include/lldb/API/SBValue.h create mode 100644 include/lldb/API/SBValueList.h create mode 100644 include/lldb/API/SBVariablesOptions.h create mode 100644 include/lldb/API/SBWatchpoint.h create mode 100644 include/lldb/API/SystemInitializerFull.h create mode 100644 include/lldb/Breakpoint/Breakpoint.h create mode 100644 include/lldb/Breakpoint/BreakpointID.h create mode 100644 include/lldb/Breakpoint/BreakpointIDList.h create mode 100644 include/lldb/Breakpoint/BreakpointList.h create mode 100644 include/lldb/Breakpoint/BreakpointLocation.h create mode 100644 include/lldb/Breakpoint/BreakpointLocationCollection.h create mode 100644 include/lldb/Breakpoint/BreakpointLocationList.h create mode 100644 include/lldb/Breakpoint/BreakpointOptions.h create mode 100644 include/lldb/Breakpoint/BreakpointResolver.h create mode 100644 include/lldb/Breakpoint/BreakpointResolverAddress.h create mode 100644 include/lldb/Breakpoint/BreakpointResolverFileLine.h create mode 100644 include/lldb/Breakpoint/BreakpointResolverFileRegex.h create mode 100644 include/lldb/Breakpoint/BreakpointResolverName.h create mode 100644 include/lldb/Breakpoint/BreakpointSite.h create mode 100644 include/lldb/Breakpoint/BreakpointSiteList.h create mode 100644 include/lldb/Breakpoint/Stoppoint.h create mode 100644 include/lldb/Breakpoint/StoppointCallbackContext.h create mode 100644 include/lldb/Breakpoint/StoppointLocation.h create mode 100644 include/lldb/Breakpoint/Watchpoint.h create mode 100644 include/lldb/Breakpoint/WatchpointList.h create mode 100644 include/lldb/Breakpoint/WatchpointOptions.h create mode 100644 include/lldb/Core/Address.h create mode 100644 include/lldb/Core/AddressRange.h create mode 100644 include/lldb/Core/AddressResolver.h create mode 100644 include/lldb/Core/AddressResolverFileLine.h create mode 100644 include/lldb/Core/AddressResolverName.h create mode 100644 include/lldb/Core/ArchSpec.h create mode 100644 include/lldb/Core/Broadcaster.h create mode 100644 include/lldb/Core/ClangForward.h create mode 100644 include/lldb/Core/Communication.h create mode 100644 include/lldb/Core/Debugger.h create mode 100644 include/lldb/Core/Disassembler.h create mode 100644 include/lldb/Core/DumpDataExtractor.h create mode 100644 include/lldb/Core/EmulateInstruction.h create mode 100644 include/lldb/Core/Event.h create mode 100644 include/lldb/Core/FileLineResolver.h create mode 100644 include/lldb/Core/FileSpecList.h create mode 100644 include/lldb/Core/FormatEntity.h create mode 100644 include/lldb/Core/IOHandler.h create mode 100644 include/lldb/Core/IOStreamMacros.h create mode 100644 include/lldb/Core/Listener.h create mode 100644 include/lldb/Core/LoadedModuleInfoList.h create mode 100644 include/lldb/Core/Mangled.h create mode 100644 include/lldb/Core/MappedHash.h create mode 100644 include/lldb/Core/Module.h create mode 100644 include/lldb/Core/ModuleChild.h create mode 100644 include/lldb/Core/ModuleList.h create mode 100644 include/lldb/Core/ModuleSpec.h create mode 100644 include/lldb/Core/Opcode.h create mode 100644 include/lldb/Core/PluginInterface.h create mode 100644 include/lldb/Core/PluginManager.h create mode 100644 include/lldb/Core/RangeMap.h create mode 100644 include/lldb/Core/RegisterValue.h create mode 100644 include/lldb/Core/STLUtils.h create mode 100644 include/lldb/Core/Scalar.h create mode 100644 include/lldb/Core/SearchFilter.h create mode 100644 include/lldb/Core/Section.h create mode 100644 include/lldb/Core/SourceManager.h create mode 100644 include/lldb/Core/State.h create mode 100644 include/lldb/Core/StreamAsynchronousIO.h create mode 100644 include/lldb/Core/StreamBuffer.h create mode 100644 include/lldb/Core/StreamFile.h create mode 100644 include/lldb/Core/StructuredDataImpl.h create mode 100644 include/lldb/Core/ThreadSafeDenseMap.h create mode 100644 include/lldb/Core/ThreadSafeDenseSet.h create mode 100644 include/lldb/Core/ThreadSafeSTLMap.h create mode 100644 include/lldb/Core/ThreadSafeSTLVector.h create mode 100644 include/lldb/Core/ThreadSafeValue.h create mode 100644 include/lldb/Core/UniqueCStringMap.h create mode 100644 include/lldb/Core/UserSettingsController.h create mode 100644 include/lldb/Core/Value.h create mode 100644 include/lldb/Core/ValueObject.h create mode 100644 include/lldb/Core/ValueObjectCast.h create mode 100644 include/lldb/Core/ValueObjectChild.h create mode 100644 include/lldb/Core/ValueObjectConstResult.h create mode 100644 include/lldb/Core/ValueObjectConstResultCast.h create mode 100644 include/lldb/Core/ValueObjectConstResultChild.h create mode 100644 include/lldb/Core/ValueObjectConstResultImpl.h create mode 100644 include/lldb/Core/ValueObjectDynamicValue.h create mode 100644 include/lldb/Core/ValueObjectList.h create mode 100644 include/lldb/Core/ValueObjectMemory.h create mode 100644 include/lldb/Core/ValueObjectRegister.h create mode 100644 include/lldb/Core/ValueObjectSyntheticFilter.h create mode 100644 include/lldb/Core/ValueObjectVariable.h create mode 100644 include/lldb/Core/dwarf.h create mode 100644 include/lldb/DataFormatters/CXXFunctionPointer.h create mode 100644 include/lldb/DataFormatters/DataVisualization.h create mode 100644 include/lldb/DataFormatters/DumpValueObjectOptions.h create mode 100644 include/lldb/DataFormatters/FormatCache.h create mode 100644 include/lldb/DataFormatters/FormatClasses.h create mode 100644 include/lldb/DataFormatters/FormatManager.h create mode 100644 include/lldb/DataFormatters/FormattersContainer.h create mode 100644 include/lldb/DataFormatters/FormattersHelpers.h create mode 100644 include/lldb/DataFormatters/LanguageCategory.h create mode 100644 include/lldb/DataFormatters/StringPrinter.h create mode 100644 include/lldb/DataFormatters/TypeCategory.h create mode 100644 include/lldb/DataFormatters/TypeCategoryMap.h create mode 100644 include/lldb/DataFormatters/TypeFormat.h create mode 100644 include/lldb/DataFormatters/TypeSummary.h create mode 100644 include/lldb/DataFormatters/TypeSynthetic.h create mode 100644 include/lldb/DataFormatters/TypeValidator.h create mode 100644 include/lldb/DataFormatters/ValueObjectPrinter.h create mode 100644 include/lldb/DataFormatters/VectorIterator.h create mode 100644 include/lldb/DataFormatters/VectorType.h create mode 100644 include/lldb/Expression/DWARFExpression.h create mode 100644 include/lldb/Expression/DiagnosticManager.h create mode 100644 include/lldb/Expression/Expression.h create mode 100644 include/lldb/Expression/ExpressionParser.h create mode 100644 include/lldb/Expression/ExpressionSourceCode.h create mode 100644 include/lldb/Expression/ExpressionTypeSystemHelper.h create mode 100644 include/lldb/Expression/ExpressionVariable.h create mode 100644 include/lldb/Expression/FunctionCaller.h create mode 100644 include/lldb/Expression/IRDynamicChecks.h create mode 100644 include/lldb/Expression/IRExecutionUnit.h create mode 100644 include/lldb/Expression/IRInterpreter.h create mode 100644 include/lldb/Expression/IRMemoryMap.h create mode 100644 include/lldb/Expression/LLVMUserExpression.h create mode 100644 include/lldb/Expression/Materializer.h create mode 100644 include/lldb/Expression/REPL.h create mode 100644 include/lldb/Expression/UserExpression.h create mode 100644 include/lldb/Expression/UtilityFunction.h create mode 100644 include/lldb/Host/Config.h create mode 100644 include/lldb/Host/Config.h.cmake create mode 100644 include/lldb/Host/ConnectionFileDescriptor.h create mode 100644 include/lldb/Host/Debug.h create mode 100644 include/lldb/Host/Editline.h create mode 100644 include/lldb/Host/File.h create mode 100644 include/lldb/Host/FileCache.h create mode 100644 include/lldb/Host/FileSystem.h create mode 100644 include/lldb/Host/Host.h create mode 100644 include/lldb/Host/HostGetOpt.h create mode 100644 include/lldb/Host/HostInfo.h create mode 100644 include/lldb/Host/HostInfoBase.h create mode 100644 include/lldb/Host/HostNativeProcess.h create mode 100644 include/lldb/Host/HostNativeProcessBase.h create mode 100644 include/lldb/Host/HostNativeThread.h create mode 100644 include/lldb/Host/HostNativeThreadBase.h create mode 100644 include/lldb/Host/HostNativeThreadForward.h create mode 100644 include/lldb/Host/HostProcess.h create mode 100644 include/lldb/Host/HostThread.h create mode 100644 include/lldb/Host/LockFile.h create mode 100644 include/lldb/Host/LockFileBase.h create mode 100644 include/lldb/Host/MainLoop.h create mode 100644 include/lldb/Host/MainLoopBase.h create mode 100644 include/lldb/Host/MonitoringProcessLauncher.h create mode 100644 include/lldb/Host/OptionParser.h create mode 100644 include/lldb/Host/Pipe.h create mode 100644 include/lldb/Host/PipeBase.h create mode 100644 include/lldb/Host/PosixApi.h create mode 100644 include/lldb/Host/Predicate.h create mode 100644 include/lldb/Host/ProcessLauncher.h create mode 100644 include/lldb/Host/ProcessRunLock.h create mode 100644 include/lldb/Host/PseudoTerminal.h create mode 100644 include/lldb/Host/Socket.h create mode 100644 include/lldb/Host/SocketAddress.h create mode 100644 include/lldb/Host/StringConvert.h create mode 100644 include/lldb/Host/Symbols.h create mode 100644 include/lldb/Host/Terminal.h create mode 100644 include/lldb/Host/ThreadLauncher.h create mode 100644 include/lldb/Host/Time.h create mode 100644 include/lldb/Host/XML.h create mode 100644 include/lldb/Host/android/HostInfoAndroid.h create mode 100644 include/lldb/Host/common/GetOptInc.h create mode 100644 include/lldb/Host/common/NativeBreakpoint.h create mode 100644 include/lldb/Host/common/NativeBreakpointList.h create mode 100644 include/lldb/Host/common/NativeProcessProtocol.h create mode 100644 include/lldb/Host/common/NativeRegisterContext.h create mode 100644 include/lldb/Host/common/NativeThreadProtocol.h create mode 100644 include/lldb/Host/common/NativeWatchpointList.h create mode 100644 include/lldb/Host/common/SoftwareBreakpoint.h create mode 100644 include/lldb/Host/common/TCPSocket.h create mode 100644 include/lldb/Host/common/UDPSocket.h create mode 100644 include/lldb/Host/freebsd/HostInfoFreeBSD.h create mode 100644 include/lldb/Host/linux/AbstractSocket.h create mode 100644 include/lldb/Host/linux/HostInfoLinux.h create mode 100644 include/lldb/Host/linux/Ptrace.h create mode 100644 include/lldb/Host/linux/Support.h create mode 100644 include/lldb/Host/linux/Uio.h create mode 100644 include/lldb/Host/macosx/HostInfoMacOSX.h create mode 100644 include/lldb/Host/macosx/HostThreadMacOSX.h create mode 100644 include/lldb/Host/netbsd/HostInfoNetBSD.h create mode 100644 include/lldb/Host/openbsd/HostInfoOpenBSD.h create mode 100644 include/lldb/Host/posix/ConnectionFileDescriptorPosix.h create mode 100644 include/lldb/Host/posix/DomainSocket.h create mode 100644 include/lldb/Host/posix/Fcntl.h create mode 100644 include/lldb/Host/posix/HostInfoPosix.h create mode 100644 include/lldb/Host/posix/HostProcessPosix.h create mode 100644 include/lldb/Host/posix/HostThreadPosix.h create mode 100644 include/lldb/Host/posix/LockFilePosix.h create mode 100644 include/lldb/Host/posix/PipePosix.h create mode 100644 include/lldb/Host/posix/ProcessLauncherPosixFork.h create mode 100644 include/lldb/Host/windows/AutoHandle.h create mode 100644 include/lldb/Host/windows/ConnectionGenericFileWindows.h create mode 100644 include/lldb/Host/windows/HostInfoWindows.h create mode 100644 include/lldb/Host/windows/HostProcessWindows.h create mode 100644 include/lldb/Host/windows/HostThreadWindows.h create mode 100644 include/lldb/Host/windows/LockFileWindows.h create mode 100644 include/lldb/Host/windows/PipeWindows.h create mode 100644 include/lldb/Host/windows/PosixApi.h create mode 100644 include/lldb/Host/windows/ProcessLauncherWindows.h create mode 100644 include/lldb/Host/windows/editlinewin.h create mode 100644 include/lldb/Host/windows/windows.h create mode 100644 include/lldb/Initialization/SystemInitializer.h create mode 100644 include/lldb/Initialization/SystemInitializerCommon.h create mode 100644 include/lldb/Initialization/SystemLifetimeManager.h create mode 100644 include/lldb/Interpreter/Args.h create mode 100644 include/lldb/Interpreter/CommandAlias.h create mode 100644 include/lldb/Interpreter/CommandCompletions.h create mode 100644 include/lldb/Interpreter/CommandHistory.h create mode 100644 include/lldb/Interpreter/CommandInterpreter.h create mode 100644 include/lldb/Interpreter/CommandObject.h create mode 100644 include/lldb/Interpreter/CommandObjectMultiword.h create mode 100644 include/lldb/Interpreter/CommandObjectRegexCommand.h create mode 100644 include/lldb/Interpreter/CommandOptionValidators.h create mode 100644 include/lldb/Interpreter/CommandReturnObject.h create mode 100644 include/lldb/Interpreter/OptionGroupArchitecture.h create mode 100644 include/lldb/Interpreter/OptionGroupBoolean.h create mode 100644 include/lldb/Interpreter/OptionGroupFile.h create mode 100644 include/lldb/Interpreter/OptionGroupFormat.h create mode 100644 include/lldb/Interpreter/OptionGroupOutputFile.h create mode 100644 include/lldb/Interpreter/OptionGroupPlatform.h create mode 100644 include/lldb/Interpreter/OptionGroupString.h create mode 100644 include/lldb/Interpreter/OptionGroupUInt64.h create mode 100644 include/lldb/Interpreter/OptionGroupUUID.h create mode 100644 include/lldb/Interpreter/OptionGroupValueObjectDisplay.h create mode 100644 include/lldb/Interpreter/OptionGroupVariable.h create mode 100644 include/lldb/Interpreter/OptionGroupWatchpoint.h create mode 100644 include/lldb/Interpreter/OptionValue.h create mode 100644 include/lldb/Interpreter/OptionValueArch.h create mode 100644 include/lldb/Interpreter/OptionValueArgs.h create mode 100644 include/lldb/Interpreter/OptionValueArray.h create mode 100644 include/lldb/Interpreter/OptionValueBoolean.h create mode 100644 include/lldb/Interpreter/OptionValueChar.h create mode 100644 include/lldb/Interpreter/OptionValueDictionary.h create mode 100644 include/lldb/Interpreter/OptionValueEnumeration.h create mode 100644 include/lldb/Interpreter/OptionValueFileSpec.h create mode 100644 include/lldb/Interpreter/OptionValueFileSpecList.h create mode 100644 include/lldb/Interpreter/OptionValueFormat.h create mode 100644 include/lldb/Interpreter/OptionValueFormatEntity.h create mode 100644 include/lldb/Interpreter/OptionValueLanguage.h create mode 100644 include/lldb/Interpreter/OptionValuePathMappings.h create mode 100644 include/lldb/Interpreter/OptionValueProperties.h create mode 100644 include/lldb/Interpreter/OptionValueRegex.h create mode 100644 include/lldb/Interpreter/OptionValueSInt64.h create mode 100644 include/lldb/Interpreter/OptionValueString.h create mode 100644 include/lldb/Interpreter/OptionValueUInt64.h create mode 100644 include/lldb/Interpreter/OptionValueUUID.h create mode 100644 include/lldb/Interpreter/OptionValues.h create mode 100644 include/lldb/Interpreter/Options.h create mode 100644 include/lldb/Interpreter/Property.h create mode 100644 include/lldb/Interpreter/ScriptInterpreter.h create mode 100644 include/lldb/Symbol/ArmUnwindInfo.h create mode 100644 include/lldb/Symbol/Block.h create mode 100644 include/lldb/Symbol/ClangASTContext.h create mode 100644 include/lldb/Symbol/ClangASTImporter.h create mode 100644 include/lldb/Symbol/ClangExternalASTSourceCallbacks.h create mode 100644 include/lldb/Symbol/ClangExternalASTSourceCommon.h create mode 100644 include/lldb/Symbol/ClangUtil.h create mode 100644 include/lldb/Symbol/CompactUnwindInfo.h create mode 100644 include/lldb/Symbol/CompileUnit.h create mode 100644 include/lldb/Symbol/CompilerDecl.h create mode 100644 include/lldb/Symbol/CompilerDeclContext.h create mode 100644 include/lldb/Symbol/CompilerType.h create mode 100644 include/lldb/Symbol/DWARFCallFrameInfo.h create mode 100644 include/lldb/Symbol/DebugMacros.h create mode 100644 include/lldb/Symbol/DeclVendor.h create mode 100644 include/lldb/Symbol/Declaration.h create mode 100644 include/lldb/Symbol/FuncUnwinders.h create mode 100644 include/lldb/Symbol/Function.h create mode 100644 include/lldb/Symbol/GoASTContext.h create mode 100644 include/lldb/Symbol/JavaASTContext.h create mode 100644 include/lldb/Symbol/LineEntry.h create mode 100644 include/lldb/Symbol/LineTable.h create mode 100644 include/lldb/Symbol/OCamlASTContext.h create mode 100644 include/lldb/Symbol/ObjectContainer.h create mode 100644 include/lldb/Symbol/ObjectFile.h create mode 100644 include/lldb/Symbol/Symbol.h create mode 100644 include/lldb/Symbol/SymbolContext.h create mode 100644 include/lldb/Symbol/SymbolContextScope.h create mode 100644 include/lldb/Symbol/SymbolFile.h create mode 100644 include/lldb/Symbol/SymbolVendor.h create mode 100644 include/lldb/Symbol/Symtab.h create mode 100644 include/lldb/Symbol/TaggedASTType.h create mode 100644 include/lldb/Symbol/Type.h create mode 100644 include/lldb/Symbol/TypeList.h create mode 100644 include/lldb/Symbol/TypeMap.h create mode 100644 include/lldb/Symbol/TypeSystem.h create mode 100644 include/lldb/Symbol/UnwindPlan.h create mode 100644 include/lldb/Symbol/UnwindTable.h create mode 100644 include/lldb/Symbol/Variable.h create mode 100644 include/lldb/Symbol/VariableList.h create mode 100644 include/lldb/Symbol/VerifyDecl.h create mode 100644 include/lldb/Target/ABI.h create mode 100644 include/lldb/Target/CPPLanguageRuntime.h create mode 100644 include/lldb/Target/DynamicLoader.h create mode 100644 include/lldb/Target/ExecutionContext.h create mode 100644 include/lldb/Target/ExecutionContextScope.h create mode 100644 include/lldb/Target/FileAction.h create mode 100644 include/lldb/Target/InstrumentationRuntime.h create mode 100644 include/lldb/Target/InstrumentationRuntimeStopInfo.h create mode 100644 include/lldb/Target/JITLoader.h create mode 100644 include/lldb/Target/JITLoaderList.h create mode 100644 include/lldb/Target/Language.h create mode 100644 include/lldb/Target/LanguageRuntime.h create mode 100644 include/lldb/Target/Memory.h create mode 100644 include/lldb/Target/MemoryHistory.h create mode 100644 include/lldb/Target/MemoryRegionInfo.h create mode 100644 include/lldb/Target/ModuleCache.h create mode 100644 include/lldb/Target/ObjCLanguageRuntime.h create mode 100644 include/lldb/Target/OperatingSystem.h create mode 100644 include/lldb/Target/PathMappingList.h create mode 100644 include/lldb/Target/Platform.h create mode 100644 include/lldb/Target/Process.h create mode 100644 include/lldb/Target/ProcessInfo.h create mode 100644 include/lldb/Target/ProcessLaunchInfo.h create mode 100644 include/lldb/Target/ProcessStructReader.h create mode 100644 include/lldb/Target/Queue.h create mode 100644 include/lldb/Target/QueueItem.h create mode 100644 include/lldb/Target/QueueList.h create mode 100644 include/lldb/Target/RegisterCheckpoint.h create mode 100644 include/lldb/Target/RegisterContext.h create mode 100644 include/lldb/Target/RegisterNumber.h create mode 100644 include/lldb/Target/SectionLoadHistory.h create mode 100644 include/lldb/Target/SectionLoadList.h create mode 100644 include/lldb/Target/StackFrame.h create mode 100644 include/lldb/Target/StackFrameList.h create mode 100644 include/lldb/Target/StackID.h create mode 100644 include/lldb/Target/StopInfo.h create mode 100644 include/lldb/Target/StructuredDataPlugin.h create mode 100644 include/lldb/Target/SystemRuntime.h create mode 100644 include/lldb/Target/Target.h create mode 100644 include/lldb/Target/TargetList.h create mode 100644 include/lldb/Target/Thread.h create mode 100644 include/lldb/Target/ThreadCollection.h create mode 100644 include/lldb/Target/ThreadList.h create mode 100644 include/lldb/Target/ThreadPlan.h create mode 100644 include/lldb/Target/ThreadPlanBase.h create mode 100644 include/lldb/Target/ThreadPlanCallFunction.h create mode 100644 include/lldb/Target/ThreadPlanCallFunctionUsingABI.h create mode 100644 include/lldb/Target/ThreadPlanCallOnFunctionExit.h create mode 100644 include/lldb/Target/ThreadPlanCallUserExpression.h create mode 100644 include/lldb/Target/ThreadPlanPython.h create mode 100644 include/lldb/Target/ThreadPlanRunToAddress.h create mode 100644 include/lldb/Target/ThreadPlanShouldStopHere.h create mode 100644 include/lldb/Target/ThreadPlanStepInRange.h create mode 100644 include/lldb/Target/ThreadPlanStepInstruction.h create mode 100644 include/lldb/Target/ThreadPlanStepOut.h create mode 100644 include/lldb/Target/ThreadPlanStepOverBreakpoint.h create mode 100644 include/lldb/Target/ThreadPlanStepOverRange.h create mode 100644 include/lldb/Target/ThreadPlanStepRange.h create mode 100644 include/lldb/Target/ThreadPlanStepThrough.h create mode 100644 include/lldb/Target/ThreadPlanStepUntil.h create mode 100644 include/lldb/Target/ThreadPlanTracer.h create mode 100644 include/lldb/Target/ThreadSpec.h create mode 100644 include/lldb/Target/UnixSignals.h create mode 100644 include/lldb/Target/Unwind.h create mode 100644 include/lldb/Target/UnwindAssembly.h create mode 100644 include/lldb/Utility/AnsiTerminal.h create mode 100644 include/lldb/Utility/Baton.h create mode 100644 include/lldb/Utility/CleanUp.h create mode 100644 include/lldb/Utility/Connection.h create mode 100644 include/lldb/Utility/ConstString.h create mode 100644 include/lldb/Utility/DataBuffer.h create mode 100644 include/lldb/Utility/DataBufferHeap.h create mode 100644 include/lldb/Utility/DataBufferLLVM.h create mode 100644 include/lldb/Utility/DataEncoder.h create mode 100644 include/lldb/Utility/DataExtractor.h create mode 100644 include/lldb/Utility/Either.h create mode 100644 include/lldb/Utility/Endian.h create mode 100644 include/lldb/Utility/FastDemangle.h create mode 100644 include/lldb/Utility/FileSpec.h create mode 100644 include/lldb/Utility/Flags.h create mode 100644 include/lldb/Utility/History.h create mode 100644 include/lldb/Utility/IOObject.h create mode 100644 include/lldb/Utility/Iterable.h create mode 100644 include/lldb/Utility/JSON.h create mode 100644 include/lldb/Utility/LLDBAssert.h create mode 100644 include/lldb/Utility/Log.h create mode 100644 include/lldb/Utility/Logging.h create mode 100644 include/lldb/Utility/NameMatches.h create mode 100644 include/lldb/Utility/Range.h create mode 100644 include/lldb/Utility/RegularExpression.h create mode 100644 include/lldb/Utility/SafeMachO.h create mode 100644 include/lldb/Utility/SelectHelper.h create mode 100644 include/lldb/Utility/SharedCluster.h create mode 100644 include/lldb/Utility/SharingPtr.h create mode 100644 include/lldb/Utility/Status.h create mode 100644 include/lldb/Utility/Stream.h create mode 100644 include/lldb/Utility/StreamCallback.h create mode 100644 include/lldb/Utility/StreamGDBRemote.h create mode 100644 include/lldb/Utility/StreamString.h create mode 100644 include/lldb/Utility/StreamTee.h create mode 100644 include/lldb/Utility/StringExtractor.h create mode 100644 include/lldb/Utility/StringLexer.h create mode 100644 include/lldb/Utility/StringList.h create mode 100644 include/lldb/Utility/StructuredData.h create mode 100644 include/lldb/Utility/TaskPool.h create mode 100644 include/lldb/Utility/TildeExpressionResolver.h create mode 100644 include/lldb/Utility/Timeout.h create mode 100644 include/lldb/Utility/Timer.h create mode 100644 include/lldb/Utility/TraceOptions.h create mode 100644 include/lldb/Utility/UUID.h create mode 100644 include/lldb/Utility/UriParser.h create mode 100644 include/lldb/Utility/UserID.h create mode 100644 include/lldb/Utility/VASPrintf.h create mode 100644 include/lldb/Utility/VMRange.h create mode 100644 include/lldb/lldb-defines.h create mode 100644 include/lldb/lldb-enumerations.h create mode 100644 include/lldb/lldb-forward.h create mode 100644 include/lldb/lldb-private-defines.h create mode 100644 include/lldb/lldb-private-enumerations.h create mode 100644 include/lldb/lldb-private-forward.h create mode 100644 include/lldb/lldb-private-interfaces.h create mode 100644 include/lldb/lldb-private-types.h create mode 100644 include/lldb/lldb-private.h create mode 100644 include/lldb/lldb-public.h create mode 100644 include/lldb/lldb-types.h create mode 100644 include/lldb/lldb-versioning.h create mode 100644 lit/CMakeLists.txt create mode 100644 lit/Expr/Inputs/anonymous-struct.cpp create mode 100644 lit/Expr/Inputs/call-function.cpp create mode 100644 lit/Expr/TestCallStdStringFunction.test create mode 100644 lit/Expr/TestCallStopAndContinue.test create mode 100644 lit/Expr/TestCallUserAnonTypedef.test create mode 100644 lit/Expr/TestCallUserDefinedFunction.test create mode 100644 lit/Expr/lit.local.cfg create mode 100644 lit/Unit/lit.cfg create mode 100644 lit/Unit/lit.site.cfg.in create mode 100644 lit/lit.cfg create mode 100644 lit/lit.site.cfg.in create mode 100644 lldb.xcodeproj/project.pbxproj create mode 100644 lldb.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/LLDB.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/Run Testsuite.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/darwin-debug.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/desktop.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/launcherRootXPCService.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/launcherXPCService.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/lldb-gtest.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/lldb-python-test-suite.xcscheme create mode 100644 lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme create mode 100644 lldb.xcworkspace/contents.xcworkspacedata create mode 100644 packages/Python/lldbsuite/.clang-format create mode 100644 packages/Python/lldbsuite/__init__.py create mode 100644 packages/Python/lldbsuite/pre_kill_hook/README.md create mode 100644 packages/Python/lldbsuite/pre_kill_hook/__init__.py create mode 100644 packages/Python/lldbsuite/pre_kill_hook/darwin.py create mode 100644 packages/Python/lldbsuite/pre_kill_hook/linux.py create mode 100644 packages/Python/lldbsuite/pre_kill_hook/tests/__init__.py create mode 100644 packages/Python/lldbsuite/pre_kill_hook/tests/test_darwin.py create mode 100644 packages/Python/lldbsuite/pre_kill_hook/tests/test_linux.py create mode 100644 packages/Python/lldbsuite/support/__init__.py create mode 100644 packages/Python/lldbsuite/support/encoded_file.py create mode 100644 packages/Python/lldbsuite/support/fs.py create mode 100644 packages/Python/lldbsuite/support/funcutils.py create mode 100644 packages/Python/lldbsuite/support/gmodules.py create mode 100644 packages/Python/lldbsuite/support/optional_with.py create mode 100644 packages/Python/lldbsuite/support/seven.py create mode 100644 packages/Python/lldbsuite/support/sockutil.py create mode 100644 packages/Python/lldbsuite/test/.categories create mode 100644 packages/Python/lldbsuite/test/Makefile create mode 100644 packages/Python/lldbsuite/test/README-TestSuite create mode 100644 packages/Python/lldbsuite/test/__init__.py create mode 100644 packages/Python/lldbsuite/test/android/platform/Makefile create mode 100644 packages/Python/lldbsuite/test/android/platform/TestDefaultCacheLineSize.py create mode 100644 packages/Python/lldbsuite/test/android/platform/main.cpp create mode 100644 packages/Python/lldbsuite/test/api/check_public_api_headers/Makefile create mode 100644 packages/Python/lldbsuite/test/api/check_public_api_headers/TestPublicAPIHeaders.py create mode 100644 packages/Python/lldbsuite/test/api/check_public_api_headers/main.cpp.template create mode 100644 packages/Python/lldbsuite/test/api/listeners/Makefile create mode 100644 packages/Python/lldbsuite/test/api/listeners/TestListener.py create mode 100644 packages/Python/lldbsuite/test/api/listeners/main.c create mode 100644 packages/Python/lldbsuite/test/api/multiple-debuggers/.categories create mode 100644 packages/Python/lldbsuite/test/api/multiple-debuggers/Makefile create mode 100644 packages/Python/lldbsuite/test/api/multiple-debuggers/TestMultipleDebuggers.py create mode 100644 packages/Python/lldbsuite/test/api/multiple-debuggers/multi-process-driver.cpp create mode 100644 packages/Python/lldbsuite/test/api/multiple-debuggers/testprog.cpp create mode 100644 packages/Python/lldbsuite/test/api/multiple-targets/Makefile create mode 100644 packages/Python/lldbsuite/test/api/multiple-targets/TestMultipleTargets.py create mode 100644 packages/Python/lldbsuite/test/api/multiple-targets/main.cpp create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/Makefile create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/common.h create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/driver.cpp.template create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/inferior.cpp create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/listener_test.cpp.template create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/test_breakpoint_callback.cpp.template create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_description.cpp.template create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/test_listener_event_process_state.cpp.template create mode 100644 packages/Python/lldbsuite/test/api/multithreaded/test_listener_resume.cpp.template create mode 100644 packages/Python/lldbsuite/test/arm_emulation/TestEmulations.py create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-10-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-11-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-12-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-4-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-5-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-5-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-6-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-6-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-7-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-7-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-8-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-8-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-add-9-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-bic-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-bic-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldmia-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldmia-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldmia-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldmia-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldmia-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldmia-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-10-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-11-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-12-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-4-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-5-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-5-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-6-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-6-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-7-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-7-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-8-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-8-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldr-9-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldrd-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldrd-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldrd-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldrh-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldrsh-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-ldrsh-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-10-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-11-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-12-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-13-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-14-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-15-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-16-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-17-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-18-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-19-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-20-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-21-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-22-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-23-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-24-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-25-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-26-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-27-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-28-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-29-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-30-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-31-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-4-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-5-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-5-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-6-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-6-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-7-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-8-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mov-9-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-moveq-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-movs-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-4-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-mvn-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-pop-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-pop-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-pop-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-pop-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-pop-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-push-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-push-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-push-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-push-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-push-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-push-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-4-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-str-5-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-strb-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-strb-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-strbt-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-strd-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-strt-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-10-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-2-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-3-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-4-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-5-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-5-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-6-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-6-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-8-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-sub-9-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-1-arm.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-10-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-4-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-5-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-6-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-8-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-subs-9-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-vpop-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-vpop-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-vpop-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-vpush-1-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-vpush-2-thumb.dat create mode 100644 packages/Python/lldbsuite/test/arm_emulation/new-test-files/test-vpush-3-thumb.dat create mode 100644 packages/Python/lldbsuite/test/attic/dotest.pl create mode 100644 packages/Python/lldbsuite/test/attic/tester.py create mode 100644 packages/Python/lldbsuite/test/bench-history create mode 100644 packages/Python/lldbsuite/test/bench.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/continue/Makefile create mode 100644 packages/Python/lldbsuite/test/benchmarks/continue/TestBenchmarkContinue.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/continue/main.cpp create mode 100644 packages/Python/lldbsuite/test/benchmarks/disassembly/TestDisassembly.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/disassembly/TestDoAttachThenDisassembly.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/disassembly/TestXcode41Vs42GDBDisassembly.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/expression/Makefile create mode 100644 packages/Python/lldbsuite/test/benchmarks/expression/TestExpressionCmd.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/expression/TestRepeatedExprs.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/expression/main.cpp create mode 100644 packages/Python/lldbsuite/test/benchmarks/frame_variable/TestFrameVariableResponse.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/libcxxlist/Makefile create mode 100644 packages/Python/lldbsuite/test/benchmarks/libcxxlist/TestBenchmarkLibcxxList.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/libcxxlist/main.cpp create mode 100644 packages/Python/lldbsuite/test/benchmarks/libcxxmap/Makefile create mode 100644 packages/Python/lldbsuite/test/benchmarks/libcxxmap/TestBenchmarkLibcxxMap.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/libcxxmap/main.cpp create mode 100644 packages/Python/lldbsuite/test/benchmarks/startup/TestStartupDelays.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/stepping/TestSteppingSpeed.py create mode 100644 packages/Python/lldbsuite/test/benchmarks/turnaround/TestCompileRunToBreakpointTurnaround.py create mode 100644 packages/Python/lldbsuite/test/concurrent_base.py create mode 100644 packages/Python/lldbsuite/test/configuration.py create mode 100644 packages/Python/lldbsuite/test/crashinfo.c create mode 100644 packages/Python/lldbsuite/test/darwin_log.py create mode 100644 packages/Python/lldbsuite/test/decorators.py create mode 100644 packages/Python/lldbsuite/test/dosep.py create mode 100644 packages/Python/lldbsuite/test/dotest.py create mode 100644 packages/Python/lldbsuite/test/dotest_args.py create mode 100644 packages/Python/lldbsuite/test/driver/batch_mode/Makefile create mode 100644 packages/Python/lldbsuite/test/driver/batch_mode/TestBatchMode.py create mode 100644 packages/Python/lldbsuite/test/driver/batch_mode/main.c create mode 100644 packages/Python/lldbsuite/test/example/TestSequenceFunctions.py create mode 100644 packages/Python/lldbsuite/test/expression_command/.categories create mode 100644 packages/Python/lldbsuite/test/expression_command/anonymous-struct/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/anonymous-struct/TestCallUserAnonTypedef.py create mode 100644 packages/Python/lldbsuite/test/expression_command/anonymous-struct/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/calculator_mode/TestCalculatorMode.py create mode 100644 packages/Python/lldbsuite/test/expression_command/call-function/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/call-function/TestCallStdStringFunction.py create mode 100644 packages/Python/lldbsuite/test/expression_command/call-function/TestCallStopAndContinue.py create mode 100644 packages/Python/lldbsuite/test/expression_command/call-function/TestCallUserDefinedFunction.py create mode 100644 packages/Python/lldbsuite/test/expression_command/call-function/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/call-restarts/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/call-restarts/TestCallThatRestarts.py create mode 100644 packages/Python/lldbsuite/test/expression_command/call-restarts/lotta-signals.c create mode 100644 packages/Python/lldbsuite/test/expression_command/call-throws/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/call-throws/TestCallThatThrows.py create mode 100644 packages/Python/lldbsuite/test/expression_command/call-throws/call-throws.m create mode 100644 packages/Python/lldbsuite/test/expression_command/char/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py create mode 100644 packages/Python/lldbsuite/test/expression_command/char/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/expr-in-syscall/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/expr-in-syscall/TestExpressionInSyscall.py create mode 100644 packages/Python/lldbsuite/test/expression_command/expr-in-syscall/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/fixits/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/fixits/TestFixIts.py create mode 100644 packages/Python/lldbsuite/test/expression_command/fixits/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/formatters/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/formatters/TestFormatters.py create mode 100644 packages/Python/lldbsuite/test/expression_command/formatters/foosynth.py create mode 100644 packages/Python/lldbsuite/test/expression_command/formatters/formatters.py create mode 100644 packages/Python/lldbsuite/test/expression_command/formatters/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/TestIRInterpreterPHINodes.py create mode 100644 packages/Python/lldbsuite/test/expression_command/ir-interpreter-phi-nodes/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/ir-interpreter/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/ir-interpreter/TestIRInterpreter.py create mode 100644 packages/Python/lldbsuite/test/expression_command/ir-interpreter/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/issue_11588/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/issue_11588/Test11588.py create mode 100644 packages/Python/lldbsuite/test/expression_command/issue_11588/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/issue_11588/s11588.py create mode 100644 packages/Python/lldbsuite/test/expression_command/macros/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py create mode 100644 packages/Python/lldbsuite/test/expression_command/macros/macro1.h create mode 100644 packages/Python/lldbsuite/test/expression_command/macros/macro2.h create mode 100644 packages/Python/lldbsuite/test/expression_command/macros/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/multiline/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/multiline/TestMultilineExpressions.py create mode 100644 packages/Python/lldbsuite/test/expression_command/multiline/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/options/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/options/TestExprOptions.py create mode 100644 packages/Python/lldbsuite/test/expression_command/options/foo.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/options/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py create mode 100644 packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/main.m create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/TestPersistentPtrUpdate.py create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_ptr_update/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_types/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_types/TestNestedPersistentTypes.py create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_types/TestPersistentTypes.py create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_types/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_variables/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_variables/TestPersistentVariables.py create mode 100644 packages/Python/lldbsuite/test/expression_command/persistent_variables/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/po_verbosity/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/po_verbosity/TestPoVerbosity.py create mode 100644 packages/Python/lldbsuite/test/expression_command/po_verbosity/main.m create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_8638051/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_8638051/Test8638051.py create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_8638051/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_9531204/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_9531204/TestPrintfAfterUp.py create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_9531204/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_9673664/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_9673664/TestExprHelpExamples.py create mode 100644 packages/Python/lldbsuite/test/expression_command/radar_9673664/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/save_jit_objects/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/save_jit_objects/TestSaveJITObjects.py create mode 100644 packages/Python/lldbsuite/test/expression_command/save_jit_objects/main.c create mode 100644 packages/Python/lldbsuite/test/expression_command/test/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/test/TestExprs.py create mode 100644 packages/Python/lldbsuite/test/expression_command/test/TestExprs2.py create mode 100644 packages/Python/lldbsuite/test/expression_command/test/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/timeout/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/timeout/TestCallWithTimeout.py create mode 100644 packages/Python/lldbsuite/test/expression_command/timeout/wait-a-while.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/top-level/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/top-level/TestTopLevelExprs.py create mode 100644 packages/Python/lldbsuite/test/expression_command/top-level/dummy.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/top-level/main.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/top-level/test.cpp create mode 100644 packages/Python/lldbsuite/test/expression_command/two-files/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/two-files/TestObjCTypeQueryFromOtherCompileUnit.py create mode 100644 packages/Python/lldbsuite/test/expression_command/two-files/foo.m create mode 100644 packages/Python/lldbsuite/test/expression_command/two-files/main.m create mode 100644 packages/Python/lldbsuite/test/expression_command/unwind_expression/Makefile create mode 100644 packages/Python/lldbsuite/test/expression_command/unwind_expression/TestUnwindExpression.py create mode 100644 packages/Python/lldbsuite/test/expression_command/unwind_expression/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/abbreviation/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/abbreviation/TestAbbreviations.py create mode 100644 packages/Python/lldbsuite/test/functionalities/abbreviation/TestCommonShortSpellings.py create mode 100644 packages/Python/lldbsuite/test/functionalities/alias/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/apropos_with_process/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/apropos_with_process/TestAproposWithProcess.py create mode 100644 packages/Python/lldbsuite/test/functionalities/apropos_with_process/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/archives/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/archives/README create mode 100644 packages/Python/lldbsuite/test/functionalities/archives/TestBSDArchives.py create mode 100644 packages/Python/lldbsuite/test/functionalities/archives/a.c create mode 100644 packages/Python/lldbsuite/test/functionalities/archives/b.c create mode 100644 packages/Python/lldbsuite/test/functionalities/archives/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/asan/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/asan/TestMemoryHistory.py create mode 100644 packages/Python/lldbsuite/test/functionalities/asan/TestReportData.py create mode 100644 packages/Python/lldbsuite/test/functionalities/asan/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/attach_resume/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/attach_resume/TestAttachResume.py create mode 100644 packages/Python/lldbsuite/test/functionalities/attach_resume/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/TestFdLeak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/backticks/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/backticks/TestBackticksWithoutATarget.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestAddressBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/address_breakpoints/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/TestBreakpointCaseSensitivity.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_case_sensitivity/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommandsFromPython.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestRegexpBreakCommand.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/a.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/b.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/bktptcmd.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/TestBreakpointConditions.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_conditions/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_ids/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_ids/TestBreakpointIDs.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_ids/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_ignore_count/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_ignore_count/TestBreakpointIgnoreCount.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_ignore_count/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/TestAvoidBreakpointInDelaySlot.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_language/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_language/TestBreakpointLanguage.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_language/a.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_language/b.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_language/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_options/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_options/TestBreakpointOptions.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_options/foo.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_options/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_set_restart/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_set_restart/TestBreakpointSetRestart.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_set_restart/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/comp_dir_symlink/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/comp_dir_symlink/TestCompDirSymLink.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/comp_dir_symlink/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/TestConsecutiveBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/consecutive_breakpoints/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/cpp/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/cpp/TestCPPBreakpointLocations.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/cpp/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/cpp_exception/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/cpp_exception/TestCPPExceptionBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/cpp_exception/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/dummy_target_breakpoints/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/dummy_target_breakpoints/TestBreakpointsWithNoTargets.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/dummy_target_breakpoints/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/inlined_breakpoints/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/inlined_breakpoints/TestInlinedBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/inlined_breakpoints/basic_type.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/inlined_breakpoints/int.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/TestMoveNearest.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/foo.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/foo.h create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/move_nearest/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/objc/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/objc/TestObjCBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/objc/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/source_regexp/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/source_regexp/TestSourceRegexBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/source_regexp/a.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/source_regexp/a.h create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/source_regexp/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/TestStepOverBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/breakpoint/step_over_breakpoint/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/command_history/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/command_history/TestCommandHistory.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_regex/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/command_regex/TestCommandRegex.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/TestCommandScript.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/bug11569.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/TestImport.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/bar/bar.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/bar/barutil.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/dummymodule.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/foo/bar/foobar.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/foo/foo.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/foo/foo2.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/rdar-12586188/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/rdar-12586188/TestRdar12586188.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/rdar-12586188/fail12586188.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/rdar-12586188/fail212586188.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/thepackage/TPunitA.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/thepackage/TPunitB.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/import/thepackage/__init__.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/mysto.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/py_import create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script/welcome.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script_alias/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script_alias/TestCommandScriptAlias.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script_alias/tcsacmd.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script_immediate_output/TestCommandScriptImmediateOutput.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_script_immediate_output/custom_command.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_source/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/command_source/.lldb create mode 100644 packages/Python/lldbsuite/test/functionalities/command_source/TestCommandSource.py create mode 100644 packages/Python/lldbsuite/test/functionalities/command_source/my.py create mode 100644 packages/Python/lldbsuite/test/functionalities/completion/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/completion/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/completion/TestCompletion.py create mode 100644 packages/Python/lldbsuite/test/functionalities/completion/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/conditional_break/.lldb create mode 100644 packages/Python/lldbsuite/test/functionalities/conditional_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/conditional_break/TestConditionalBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/conditional_break/conditional_break.py create mode 100644 packages/Python/lldbsuite/test/functionalities/conditional_break/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/basic/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/basic/TestDarwinLogBasic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/basic/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/common/darwin_log_common.h create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/activity-chain/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/activity-chain/TestDarwinLogFilterMatchActivityChain.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/activity-chain/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/activity/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/activity/TestDarwinLogFilterMatchActivity.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/activity/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/category/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/category/TestDarwinLogFilterMatchCategory.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/category/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/message/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/message/TestDarwinLogFilterMatchMessage.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/message/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/subsystem/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/subsystem/TestDarwinLogFilterMatchSubsystem.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/exact_match/subsystem/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/activity-chain/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/activity-chain/TestDarwinLogFilterRegexActivityChain.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/activity-chain/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/activity/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/activity/TestDarwinLogFilterRegexActivity.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/activity/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/category/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/category/TestDarwinLogFilterRegexCategory.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/category/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/message/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/message/TestDarwinLogFilterRegexMessage.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/message/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/subsystem/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/subsystem/TestDarwinLogFilterRegexSubsystem.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/filter/regex/subsystem/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/format/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/format/TestDarwinLogMessageFormat.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/format/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/source/debug/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/source/debug/TestDarwinLogSourceDebug.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/source/debug/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/source/info/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/source/info/TestDarwinLogSourceInfo.py create mode 100644 packages/Python/lldbsuite/test/functionalities/darwin_log/source/info/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/boolreference/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/boolreference/TestFormattersBoolRefPtr.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/boolreference/main.mm create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/compactvectors/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/compactvectors/TestCompactVectors.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/compactvectors/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-advanced/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-categories/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-categories/TestDataFormatterCategories.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-categories/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-cpp/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-cpp/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-disabling/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-disabling/TestDataFormatterDisabling.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-disabling/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-enum-format/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-enum-format/TestDataFormatterEnumFormat.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-enum-format/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-globals/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-globals/TestDataFormatterGlobals.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-globals/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-named-summaries/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-named-summaries/TestDataFormatterNamedSummaries.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-named-summaries/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/nsindexpath/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/nsindexpath/TestDataFormatterNSIndexPath.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/nsindexpath/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/nsstring/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-objc/nsstring/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-proper-plurals/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-proper-plurals/TestFormattersOneIsSingular.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-proper-plurals/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-ptr-to-array/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-ptr-to-array/TestPtrToArrayFormatting.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-ptr-to-array/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/ftsp.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-python-synth/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-script/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-script/TestDataFormatterScript.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-script/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-skip-summary/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-skip-summary/TestDataFormatterSkipSummary.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-skip-summary/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-smart-array/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-smart-array/TestDataFormatterSmartArray.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-smart-array/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/atomic/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/atomic/TestLibCxxAtomic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/atomic/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/function/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/function/TestLibCxxFunction.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/function/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/initializerlist/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/initializerlist/TestInitializerList.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/initializerlist/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/list/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/list/TestDataFormatterLibcxxList.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/list/loop/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/list/loop/TestDataFormatterLibcxxListLoop.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/list/loop/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/list/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/map/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/set/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/vbool/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/vbool/TestDataFormatterLibcxxVBool.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/vbool/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/vector/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/vector/TestDataFormatterLibcxxVector.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libcxx/vector/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/iterator/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/iterator/TestDataFormatterStdIterator.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/iterator/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/TestDataFormatterStdList.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/list/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/TestDataFormatterStdMap.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/map/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/TestDataFormatterStdSmartPtr.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/smart_ptr/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/TestDataFormatterStdString.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/tuple/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/tuple/TestDataFormatterStdTuple.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/tuple/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/TestDataFormatterStdVBool.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/vbool/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVector.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synth/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synth/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthtype/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthtype/TestDataFormatterSynthType.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthtype/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthtype/myIntSynthProvider.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthval/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthval/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/dump_dynamic/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/dump_dynamic/TestDumpDynamic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/dump_dynamic/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/format-propagation/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/format-propagation/TestFormatPropagation.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/format-propagation/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/frameformat_smallstruct/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/frameformat_smallstruct/TestFrameFormatSmallStruct.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/frameformat_smallstruct/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/hexcaps/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/hexcaps/TestDataFormatterHexCaps.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/hexcaps/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/TestDataFormatterLanguageCategoryUpdates.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/language_category_updates/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nsarraysynth/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nsarraysynth/TestNSArraySynthetic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nsarraysynth/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nsdictionarysynth/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nsdictionarysynth/TestNSDictionarySynthetic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nsdictionarysynth/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nssetsynth/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nssetsynth/TestNSSetSynthetic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/nssetsynth/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/ostypeformatting/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/ostypeformatting/TestFormattersOsType.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/ostypeformatting/main.mm create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/parray/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/parray/TestPrintArray.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/parray/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/poarray/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/poarray/TestPrintObjectArray.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/poarray/main.mm create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/ptr_ref_typedef/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/ptr_ref_typedef/TestPtrRef2Typedef.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/ptr_ref_typedef/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/pyobjsynthprovider/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/pyobjsynthprovider/TestPyObjSynthProvider.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/pyobjsynthprovider/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/pyobjsynthprovider/provider.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/refpointer-recursion/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/refpointer-recursion/TestDataFormatterRefPtrRecursion.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/refpointer-recursion/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/setvaluefromcstring/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/setvaluefromcstring/TestSetValueFromCString.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/setvaluefromcstring/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/stringprinter/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/stringprinter/TestStringPrinter.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/stringprinter/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/summary-string-onfail/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/summary-string-onfail/Test-rdar-9974002.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/summary-string-onfail/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthcapping/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthcapping/TestSyntheticCapping.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthcapping/fooSynthProvider.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthcapping/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthupdate/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthupdate/TestSyntheticFilterRecompute.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/synthupdate/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/type_summary_list_arg/TestTypeSummaryListArg.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/type_summary_list_script/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/type_summary_list_script/TestTypeSummaryListScript.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/type_summary_list_script/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/type_summary_list_script/tslsformatters.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/typedef_array/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/typedef_array/TestTypedefArray.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/typedef_array/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/user-format-vs-summary/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/user-format-vs-summary/TestUserFormatVsSummary.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/user-format-vs-summary/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/var-in-aggregate-misuse/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/var-in-aggregate-misuse/TestVarInAggregateMisuse.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/var-in-aggregate-misuse/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/varscript_formatting/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/varscript_formatting/TestDataFormatterVarScriptFormatting.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/varscript_formatting/helperfunc.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/varscript_formatting/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/TestVectorTypesFormatting.py create mode 100644 packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/dead-strip/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/dead-strip/TestDeadStrip.py create mode 100644 packages/Python/lldbsuite/test/functionalities/dead-strip/cmds.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/dead-strip/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/disassembly/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/disassembly/TestDisassembleBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/disassembly/TestFrameDisassemble.py create mode 100644 packages/Python/lldbsuite/test/functionalities/disassembly/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/dynamic_value_child_count/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/dynamic_value_child_count/TestDynamicValueChildCount.py create mode 100644 packages/Python/lldbsuite/test/functionalities/dynamic_value_child_count/pass-to-base.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/embedded_interpreter/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/embedded_interpreter/TestConvenienceVariables.py create mode 100644 packages/Python/lldbsuite/test/functionalities/embedded_interpreter/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/exec/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/exec/TestExec.py create mode 100644 packages/Python/lldbsuite/test/functionalities/exec/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/expr-doesnt-deadlock/.categories create mode 100644 packages/Python/lldbsuite/test/functionalities/expr-doesnt-deadlock/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/expr-doesnt-deadlock/TestExprDoesntBlock.py create mode 100644 packages/Python/lldbsuite/test/functionalities/expr-doesnt-deadlock/locking.c create mode 100644 packages/Python/lldbsuite/test/functionalities/fat_archives/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/fat_archives/TestFatArchives.py create mode 100644 packages/Python/lldbsuite/test/functionalities/fat_archives/a.c create mode 100644 packages/Python/lldbsuite/test/functionalities/fat_archives/a.h create mode 100644 packages/Python/lldbsuite/test/functionalities/fat_archives/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/format/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/format/TestFormats.py create mode 100644 packages/Python/lldbsuite/test/functionalities/format/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/TestArray.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/array/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/TestBadReference.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/bad-reference/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/TestComplicatedExpression.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/complicated-expression/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/TestDiagnoseDereferenceArgument.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-argument/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/TestDiagnoseDereferenceFunctionReturn.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-function-return/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/TestDiagnoseDereferenceThis.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/dereference-this/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/TestDiagnoseInheritance.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/inheritance/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/TestLocalVariable.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/local-variable/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/TestDiagnoseDereferenceVirtualMethodCall.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-diagnose/virtual-method-call/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/TestGuessLanguage.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/other-2.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/other.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/other.h create mode 100644 packages/Python/lldbsuite/test/functionalities/frame-language/somefunc.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame_var/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame_var/TestFrameVar.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame_var/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/frame_var_scope/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/frame_var_scope/TestFrameVariableScope.py create mode 100644 packages/Python/lldbsuite/test/functionalities/frame_var_scope/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/history/TestHistoryRecall.py create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-assert/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-assert/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-changed/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-changed/TestInferiorChanged.py create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-changed/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-changed/main2.c create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-crashing/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-crashing/TestInferiorCrashing.py create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-crashing/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-crashing/recursive-inferior/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-crashing/recursive-inferior/TestRecursiveInferior.py create mode 100644 packages/Python/lldbsuite/test/functionalities/inferior-crashing/recursive-inferior/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/inline-stepping/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/inline-stepping/TestInlineStepping.py create mode 100644 packages/Python/lldbsuite/test/functionalities/inline-stepping/calling.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/jitloader_gdb/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/jitloader_gdb/TestJITLoaderGDB.py create mode 100644 packages/Python/lldbsuite/test/functionalities/jitloader_gdb/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/TestLaunchWithShellExpand.py create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/file1.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/file2.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/file3.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/file4.txy create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/file5.tyx create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/foo bar create mode 100644 packages/Python/lldbsuite/test/functionalities/launch_with_shellexpand/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/a.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/a.mk create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/b.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/b.mk create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/c.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/c.mk create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/cmds.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/d.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/d.mk create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/hidden/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/hidden/d.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/load_unload/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/longjmp/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/longjmp/TestLongjmp.py create mode 100644 packages/Python/lldbsuite/test/functionalities/longjmp/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/cache/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/cache/TestMemoryCache.py create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/cache/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/find/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/find/TestMemoryFind.py create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/find/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/read/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/read/TestMemoryRead.py create mode 100644 packages/Python/lldbsuite/test/functionalities/memory/read/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/mtc/simple/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/mtc/simple/TestMTCSimple.py create mode 100644 packages/Python/lldbsuite/test/functionalities/mtc/simple/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/multidebugger_commands/TestMultipleDebuggersCommands.py create mode 100644 packages/Python/lldbsuite/test/functionalities/nested_alias/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/nested_alias/TestNestedAlias.py create mode 100644 packages/Python/lldbsuite/test/functionalities/nested_alias/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/non-overlapping-index-variable-i/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/non-overlapping-index-variable-i/TestIndexVariable.py create mode 100644 packages/Python/lldbsuite/test/functionalities/non-overlapping-index-variable-i/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/nosucharch/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/nosucharch/TestNoSuchArch.py create mode 100644 packages/Python/lldbsuite/test/functionalities/nosucharch/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/TestImageListMultiArchitecture.py create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-freebsd-10.0-x86_64-clang-3.3 create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-freebsd-10.0-x86_64-gcc-4.7.3 create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-netbsd-6.1-x86_64-gcc-4.5.3 create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-ubuntu-14.04-x86_64-clang-3.5pre create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-ubuntu-14.04-x86_64-gcc-4.8.2 create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-unknown-kalimba_arch4-kcc-36 create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello-unknown-kalimba_arch5-kcc-39 create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello.c create mode 100644 packages/Python/lldbsuite/test/functionalities/object-file/bin/hello.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/paths/TestPaths.py create mode 100644 packages/Python/lldbsuite/test/functionalities/platform/TestPlatformCommand.py create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/commands/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/commands/TestPluginCommands.py create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/commands/plugin.cpp.template create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/python_os_plugin/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/python_os_plugin/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/python_os_plugin/operating_system.py create mode 100644 packages/Python/lldbsuite/test/functionalities/plugins/python_os_plugin/operating_system2.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/TestLinuxCore.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.c create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/altmain.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/fpr_sse.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/TestGCore.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-i386.core create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/linux-x86_64.core create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.cpp create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/main.mk create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/gcore/make-core.sh create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_i386.core create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-fpr_sse_x86_64.core create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-i386.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-i386.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-mips64el-gnuabi64.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-mips64el-gnuabi64.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-mips64el-gnuabin32.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-mips64el-gnuabin32.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-mipsel-gnuabio32.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-mipsel-gnuabio32.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-s390x.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-s390x.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-x86_64.core create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/linux-x86_64.out create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/main.c create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/make-core.sh create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/TestLinuxCoreThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-i386.core create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/linux-x86_64.core create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.cpp create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/main.mk create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/elf-core/thread_crash/make-core.sh create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/TestMiniDumpNew.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/install_breakpad.cpp create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64 create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.dmp create mode 100755 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64_not_crashed.dmp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/makefile.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump/TestMiniDump.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump/fizzbuzz.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump/fizzbuzz_no_heap.dmp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/minidump/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/TestWow64MiniDump.py create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/postmortem/wow64_minidump/fizzbuzz_wow64.dmp create mode 100644 packages/Python/lldbsuite/test/functionalities/pre_run_dylibs/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/pre_run_dylibs/TestPreRunDylibs.py create mode 100644 packages/Python/lldbsuite/test/functionalities/pre_run_dylibs/foo.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/pre_run_dylibs/foo.h create mode 100644 packages/Python/lldbsuite/test/functionalities/pre_run_dylibs/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/process_attach/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/process_attach/TestProcessAttach.py create mode 100644 packages/Python/lldbsuite/test/functionalities/process_attach/attach_denied/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/process_attach/attach_denied/TestAttachDenied.py create mode 100644 packages/Python/lldbsuite/test/functionalities/process_attach/attach_denied/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/process_attach/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/process_group/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/process_group/TestChangeProcessGroup.py create mode 100644 packages/Python/lldbsuite/test/functionalities/process_group/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/TestProcessLaunch.py create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/input-file.txt create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/my_working_dir/.keep create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/print_cwd.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/process_launch/print_env.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/process_save_core/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/process_save_core/TestProcessSaveCore.py create mode 100644 packages/Python/lldbsuite/test/functionalities/process_save_core/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/ptr_refs/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/ptr_refs/TestPtrRefs.py create mode 100644 packages/Python/lldbsuite/test/functionalities/ptr_refs/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/recursion/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/recursion/TestValueObjectRecursion.py create mode 100644 packages/Python/lldbsuite/test/functionalities/recursion/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_avx/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_avx/TestYMMRegister.py create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_avx/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/TestMPXRegisters.py create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/TestBoundViolation.py create mode 100644 packages/Python/lldbsuite/test/functionalities/register/intel_xtended_registers/mpx_bound_violation/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/register/register_command/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/register/register_command/TestRegisters.py create mode 100644 packages/Python/lldbsuite/test/functionalities/register/register_command/a.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/register/register_command/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/rerun/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/rerun/TestRerun.py create mode 100644 packages/Python/lldbsuite/test/functionalities/rerun/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/return-value/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py create mode 100644 packages/Python/lldbsuite/test/functionalities/return-value/call-func.c create mode 100644 packages/Python/lldbsuite/test/functionalities/set-data/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/set-data/TestSetData.py create mode 100644 packages/Python/lldbsuite/test/functionalities/set-data/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/TestSendSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/handle-segv/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/handle-segv/TestHandleSegv.py create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/handle-segv/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/raise/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/raise/TestRaise.py create mode 100644 packages/Python/lldbsuite/test/functionalities/signal/raise/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/single-quote-in-filename-to-lldb/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/single-quote-in-filename-to-lldb/TestSingleQuoteInFilename.py create mode 100644 packages/Python/lldbsuite/test/functionalities/single-quote-in-filename-to-lldb/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/single-quote-in-filename-to-lldb/path with '09/.keep create mode 100644 packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/TestStepNoDebug.py create mode 100644 packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/with-debug.c create mode 100644 packages/Python/lldbsuite/test/functionalities/step-avoids-no-debug/without-debug.c create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/TestStopHookCmd.py create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/TestStopHookMechanism.py create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/multiple_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/multiple_threads/TestStopHookMultipleThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/stop-hook/multiple_threads/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/target_command/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/target_command/TestTargetCommand.py create mode 100644 packages/Python/lldbsuite/test/functionalities/target_command/a.c create mode 100644 packages/Python/lldbsuite/test/functionalities/target_command/b.c create mode 100644 packages/Python/lldbsuite/test/functionalities/target_command/c.c create mode 100644 packages/Python/lldbsuite/test/functionalities/target_command/globals.c create mode 100644 packages/Python/lldbsuite/test/functionalities/testid/TestTestId.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/Makefile create mode 100755 packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/ParallelTask.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/backtrace_all/TestBacktraceAll.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/break_after_join/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/break_after_join/TestBreakAfterJoin.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/break_after_join/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/breakpoint_delay_breakpoint_one_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/breakpoint_delay_breakpoint_one_signal/TestConcurrentBreakpointDelayBreakpointOneSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/breakpoint_one_delay_breakpoint_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/breakpoint_one_delay_breakpoint_threads/TestConcurrentBreakpointOneDelayBreakpointThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/breakpoints_delayed_breakpoint_one_watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/breakpoints_delayed_breakpoint_one_watchpoint/TestConcurrentBreakpointsDelayedBreakpointOneWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_break/TestConcurrentCrashWithBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_signal/TestConcurrentCrashWithSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_watchpoint/TestConcurrentCrashWithWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_watchpoint_breakpoint_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/crash_with_watchpoint_breakpoint_signal/TestConcurrentCrashWithWatchpointBreakpointSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delay_signal_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delay_signal_break/TestConcurrentDelaySignalBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delay_signal_watch/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delay_signal_watch/TestConcurrentDelaySignalWatch.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delay_watch_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delay_watch_break/TestConcurrentDelayWatchBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delayed_crash_with_breakpoint_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delayed_crash_with_breakpoint_signal/TestConcurrentDelayedCrashWithBreakpointSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delayed_crash_with_breakpoint_watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/delayed_crash_with_breakpoint_watchpoint/TestConcurrentDelayedCrashWithBreakpointWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_breakpoints/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_breakpoints/TestConcurrentManyBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_crash/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_crash/TestConcurrentManyCrash.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_signals/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_signals/TestConcurrentManySignals.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_watchpoints/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/many_watchpoints/TestConcurrentManyWatchpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/n_watch_n_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/n_watch_n_break/TestConcurrentNWatchNBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_break/TestConcurrentSignalBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_delay_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_delay_break/TestConcurrentSignalDelayBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_delay_watch/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_delay_watch/TestConcurrentSignalDelayWatch.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_n_watch_n_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_n_watch_n_break/TestConcurrentSignalNWatchNBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_watch/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_watch/TestConcurrentSignalWatch.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_watch_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/signal_watch_break/TestConcurrentSignalWatchBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoint_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoint_threads/TestConcurrentTwoBreakpointThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoints_one_delay_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoints_one_delay_signal/TestConcurrentTwoBreakpointsOneDelaySignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoints_one_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoints_one_signal/TestConcurrentTwoBreakpointsOneSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoints_one_watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_breakpoints_one_watchpoint/TestConcurrentTwoBreakpointsOneWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoint_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoint_threads/TestConcurrentTwoWatchpointThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoints_one_breakpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoints_one_breakpoint/TestConcurrentTwoWatchpointsOneBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoints_one_delay_breakpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoints_one_delay_breakpoint/TestConcurrentTwoWatchpointsOneDelayBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoints_one_signal/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/two_watchpoints_one_signal/TestConcurrentTwoWatchpointsOneSignal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watch_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watch_break/TestConcurrentWatchBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watch_break_delay/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watch_break_delay/TestConcurrentWatchBreakDelay.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watchpoint_delay_watchpoint_one_breakpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watchpoint_delay_watchpoint_one_breakpoint/TestConcurrentWatchpointDelayWatchpointOneBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watchpoint_with_delay_watchpoint_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/watchpoint_with_delay_watchpoint_threads/TestConcurrentWatchpointWithDelayWatchpointThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/TestCreateAfterAttach.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/create_after_attach/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/create_during_step/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/create_during_step/TestCreateDuringStep.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/create_during_step/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/TestExitDuringBreak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/exit_during_break/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/TestExitDuringStep.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/exit_during_step/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/jump/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/jump/TestThreadJump.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/jump/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/jump/other.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/multi_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/multi_break/TestMultipleBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/multi_break/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/num_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/num_threads/TestNumThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/num_threads/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/state/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/state/TestThreadStates.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/state/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/step_out/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/step_out/TestThreadStepOut.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/step_out/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/step_until/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/step_until/TestStepUntil.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/step_until/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_exit/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_exit/TestThreadExit.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_exit/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/TestThreadSpecificBreakpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/TestThreadSpecificBpPlusCondition.py create mode 100644 packages/Python/lldbsuite/test/functionalities/thread/thread_specific_break_plus_condition/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/basic/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/basic/TestTsanBasic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/basic/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/cpp_global_location/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/cpp_global_location/TestTsanCPPGlobalLocation.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/cpp_global_location/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/global_location/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/global_location/TestTsanGlobalLocation.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/global_location/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/multiple/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/multiple/TestTsanMultiple.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/multiple/main.m create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/thread_leak/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/thread_leak/TestTsanThreadLeak.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/thread_leak/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/TestTsanThreadNumbers.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tsan/thread_numbers/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/tty/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/tty/TestTerminal.py create mode 100644 packages/Python/lldbsuite/test/functionalities/tty/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/type_completion/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/type_completion/TestTypeCompletion.py create mode 100644 packages/Python/lldbsuite/test/functionalities/type_completion/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/type_lookup/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/type_lookup/TestTypeLookup.py create mode 100644 packages/Python/lldbsuite/test/functionalities/type_lookup/main.mm create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/basic/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/basic/TestUbsanBasic.py create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/basic/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/TestUbsanUserExpression.py create mode 100644 packages/Python/lldbsuite/test/functionalities/ubsan/user-expression/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/ehframe/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/ehframe/TestEhFrameUnwind.py create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/ehframe/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/TestNoreturnUnwind.py create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/TestNoReturnModuleEnd.py create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/a.s create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.core create mode 100755 packages/Python/lldbsuite/test/functionalities/unwind/noreturn/module-end/test.out create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/TestSigtrampUnwind.py create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/sigtramp/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/standard/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/standard/TestStandardUnwind.py create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/divmod.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/fprintf.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/unwind/standard/hand_written/new_delete.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/value_md5_crash/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/value_md5_crash/TestValueMD5Crash.py create mode 100644 packages/Python/lldbsuite/test/functionalities/value_md5_crash/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchpoint/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multi_watchpoint_slots/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multi_watchpoint_slots/TestWatchpointMultipleSlots.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multi_watchpoint_slots/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multiple_hits/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multiple_hits/TestMultipleHits.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multiple_hits/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multiple_threads/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multiple_threads/TestWatchpointMultipleThreads.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/multiple_threads/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/TestStepOverWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/step_over_watchpoint/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/variable_out_of_scope/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/variable_out_of_scope/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/command/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/command/watchpoint_command.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/condition/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_commands/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_disable/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_disable/TestWatchpointDisable.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_disable/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_events/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_events/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_on_vectors/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_on_vectors/TestValueOfVectorVariable.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_on_vectors/main.c create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/TestWatchLocationWithWatchSet.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/TestWatchpointSetErrorCases.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_set_command/main.cpp create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/Makefile create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/TestWatchpointSizes.py create mode 100644 packages/Python/lldbsuite/test/functionalities/watchpoint/watchpoint_size/main.c create mode 100644 packages/Python/lldbsuite/test/help/TestApropos.py create mode 100644 packages/Python/lldbsuite/test/help/TestHelp.py create mode 100644 packages/Python/lldbsuite/test/issue_verification/Makefile create mode 100644 packages/Python/lldbsuite/test/issue_verification/README.txt create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestExpectedTimeout.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestFail.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestInvalidDecorator.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestRerunFail.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestRerunFileLevelTimeout.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestRerunInline.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestRerunTimeout.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestSignal.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestSignalOutsideTestMethod.py.park create mode 100644 packages/Python/lldbsuite/test/issue_verification/TestTimeout.py.park create mode 100755 packages/Python/lldbsuite/test/issue_verification/disable.py create mode 100755 packages/Python/lldbsuite/test/issue_verification/enable.py create mode 100644 packages/Python/lldbsuite/test/issue_verification/inline_rerun_inferior.cpp create mode 100644 packages/Python/lldbsuite/test/issue_verification/rerun_base.py create mode 100644 packages/Python/lldbsuite/test/lang/c/anonymous/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/anonymous/TestAnonymous.py create mode 100644 packages/Python/lldbsuite/test/lang/c/anonymous/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/array_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/array_types/TestArrayTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/c/array_types/cmds.txt create mode 100644 packages/Python/lldbsuite/test/lang/c/array_types/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/bitfields/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/bitfields/TestBitfields.py create mode 100644 packages/Python/lldbsuite/test/lang/c/bitfields/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/blocks/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/blocks/TestBlocks.py create mode 100644 packages/Python/lldbsuite/test/lang/c/blocks/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/One.mk create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/One/One.c create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/One/One.h create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/One/OneConstant.c create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/TestConflictingSymbol.py create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/Two.mk create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/Two/Two.c create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/Two/Two.h create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/Two/TwoConstant.c create mode 100644 packages/Python/lldbsuite/test/lang/c/conflicting-symbol/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/const_variables/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/const_variables/TestConstVariables.py create mode 100644 packages/Python/lldbsuite/test/lang/c/const_variables/functions.c create mode 100644 packages/Python/lldbsuite/test/lang/c/const_variables/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/enum_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/c/enum_types/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/find_struct_type/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/find_struct_type/TestFindStructTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/c/find_struct_type/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/forward/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/forward/README.txt create mode 100644 packages/Python/lldbsuite/test/lang/c/forward/TestForwardDeclaration.py create mode 100644 packages/Python/lldbsuite/test/lang/c/forward/foo.c create mode 100644 packages/Python/lldbsuite/test/lang/c/forward/foo.h create mode 100644 packages/Python/lldbsuite/test/lang/c/forward/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/function_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/function_types/TestFunctionTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/c/function_types/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/global_variables/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/global_variables/TestGlobalVariables.py create mode 100644 packages/Python/lldbsuite/test/lang/c/global_variables/a.c create mode 100644 packages/Python/lldbsuite/test/lang/c/global_variables/cmds.txt create mode 100644 packages/Python/lldbsuite/test/lang/c/global_variables/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/inlines/TestRedefinitionsInInlines.py create mode 100644 packages/Python/lldbsuite/test/lang/c/inlines/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/modules/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/modules/TestCModules.py create mode 100644 packages/Python/lldbsuite/test/lang/c/modules/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/recurse/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/recurse/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/register_variables/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/register_variables/TestRegisterVariables.py create mode 100644 packages/Python/lldbsuite/test/lang/c/register_variables/test.c create mode 100644 packages/Python/lldbsuite/test/lang/c/set_values/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/set_values/TestSetValues.py create mode 100644 packages/Python/lldbsuite/test/lang/c/set_values/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib/TestSharedLib.py create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib/foo.c create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib/foo.h create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib_stripped_symbols/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib_stripped_symbols/TestSharedLibStrippedSymbols.py create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib_stripped_symbols/foo.c create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib_stripped_symbols/foo.h create mode 100644 packages/Python/lldbsuite/test/lang/c/shared_lib_stripped_symbols/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/step-target/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/step-target/TestStepTarget.py create mode 100644 packages/Python/lldbsuite/test/lang/c/step-target/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/stepping/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/stepping/TestStepAndBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/lang/c/stepping/TestThreadStepping.py create mode 100644 packages/Python/lldbsuite/test/lang/c/stepping/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/strings/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/strings/TestCStrings.py create mode 100644 packages/Python/lldbsuite/test/lang/c/strings/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/struct_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/struct_types/TestStructTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/c/struct_types/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/tls_globals/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/tls_globals/TestTlsGlobals.py create mode 100644 packages/Python/lldbsuite/test/lang/c/tls_globals/a.c create mode 100644 packages/Python/lldbsuite/test/lang/c/tls_globals/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/typedef/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py create mode 100644 packages/Python/lldbsuite/test/lang/c/typedef/main.c create mode 100644 packages/Python/lldbsuite/test/lang/c/unions/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/c/unions/TestUnionMembers.py create mode 100644 packages/Python/lldbsuite/test/lang/c/unions/main.c create mode 100644 packages/Python/lldbsuite/test/lang/cpp/auto/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/auto/TestCPPAuto.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/auto/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/bool/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/bool/TestCPPBool.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/bool/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/breakpoint-commands/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/breakpoint-commands/TestCPPBreakpointCommands.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/breakpoint-commands/nested.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/call-function/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/call-function/TestCallCPPFunction.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/call-function/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/chained-calls/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/chained-calls/TestCppChainedCalls.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/chained-calls/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/char1632_t/.categories create mode 100644 packages/Python/lldbsuite/test/lang/cpp/char1632_t/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/char1632_t/TestChar1632T.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/char1632_t/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/TestClassTemplateParameterPack.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class-template-parameter-pack/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_static/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_static/TestStaticVariables.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_static/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_types/TestClassTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_types/TestClassTypesDisassembly.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_types/cmds.txt create mode 100644 packages/Python/lldbsuite/test/lang/cpp/class_types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/const_this/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/const_this/TestConstThis.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/const_this/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/diamond/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/diamond/TestDiamond.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/diamond/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/dynamic-value/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/dynamic-value/TestCppValueCast.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/dynamic-value/TestDynamicValue.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/dynamic-value/pass-to-base.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/dynamic-value/sbvalue-cast.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/enum_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/enum_types/TestCPP11EnumTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/enum_types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/exceptions/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/exceptions/TestCPPExceptionBreakpoints.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/exceptions/exceptions.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/extern_c/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/extern_c/TestExternCSymbols.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/extern_c/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/frame-var-anon-unions/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/frame-var-anon-unions/TestFrameVariableAnonymousUnions.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/frame-var-anon-unions/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/function-template-parameter-pack/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/function-template-parameter-pack/TestFunctionTemplateParameterPack.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/function-template-parameter-pack/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/global_operators/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/global_operators/TestCppGlobalOperators.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/global_operators/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/gmodules/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/gmodules/TestWithModuleDebugging.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/gmodules/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/gmodules/pch.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/TestCppIncompleteTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/a.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/a.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/length.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/length.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/incomplete-types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/inlines/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/inlines/TestInlines.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/inlines/inlines.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/inlines/inlines.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/lambdas/TestLambdas.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/lambdas/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/TestWithLimitDebugInfo.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/base.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/base.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/derived.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/derived.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/llvm-style/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/llvm-style/TestLLVMStyle.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/llvm-style/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/TestNamespace.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/TestNamespaceLookup.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/cmds.txt create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/ns.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/ns.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/ns2.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace/ns3.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_conflicts/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_conflicts/TestNamespaceConflicts.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_conflicts/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/TestNamespaceDefinitions.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/a.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/a.mk create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/b.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/b.mk create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/foo.h create mode 100644 packages/Python/lldbsuite/test/lang/cpp/namespace_definitions/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/nsimport/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/nsimport/TestCppNsImport.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/nsimport/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/overloaded-functions/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/overloaded-functions/TestOverloadedFunctions.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/overloaded-functions/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/overloaded-functions/static-a.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/overloaded-functions/static-b.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/printf/TestPrintf.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/printf/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/rvalue-references/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/rvalue-references/TestRvalueReferences.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/rvalue-references/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/scope/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/scope/TestCppScope.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/scope/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/signed_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/signed_types/TestSignedTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/signed_types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/static_members/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/static_members/TestCPPStaticMembers.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/static_members/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/static_methods/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/static_methods/TestCPPStaticMethods.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/static_methods/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/stl/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/stl/TestSTL.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/stl/TestStdCXXDisassembly.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/stl/cmds.txt create mode 100644 packages/Python/lldbsuite/test/lang/cpp/stl/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/symbols/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/symbols/TestSymbols.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/symbols/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/template/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/template/TestTemplateArgs.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/template/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/this/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/this/TestCPPThis.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/this/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unicode-literals/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unicode-literals/TestUnicodeLiterals.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unicode-literals/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unique-types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unique-types/TestUniqueTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unique-types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unsigned_types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unsigned_types/TestUnsignedTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/unsigned_types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/virtual/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/virtual/TestVirtual.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/virtual/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/cpp/wchar_t/.categories create mode 100644 packages/Python/lldbsuite/test/lang/cpp/wchar_t/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/cpp/wchar_t/TestCxxWCharT.py create mode 100644 packages/Python/lldbsuite/test/lang/cpp/wchar_t/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/go/expressions/TestExpressions.py create mode 100644 packages/Python/lldbsuite/test/lang/go/expressions/main.go create mode 100644 packages/Python/lldbsuite/test/lang/go/formatters/TestGoFormatters.py create mode 100644 packages/Python/lldbsuite/test/lang/go/formatters/main.go create mode 100644 packages/Python/lldbsuite/test/lang/go/goroutines/TestGoroutines.py create mode 100644 packages/Python/lldbsuite/test/lang/go/goroutines/main.go create mode 100644 packages/Python/lldbsuite/test/lang/go/runtime/TestGoLanguageRuntime create mode 100644 packages/Python/lldbsuite/test/lang/go/runtime/main.go create mode 100644 packages/Python/lldbsuite/test/lang/go/types/TestGoASTContext.py create mode 100644 packages/Python/lldbsuite/test/lang/go/types/main.go create mode 100644 packages/Python/lldbsuite/test/lang/mixed/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/mixed/TestMixedLanguages.py create mode 100644 packages/Python/lldbsuite/test/lang/mixed/foo.cpp create mode 100644 packages/Python/lldbsuite/test/lang/mixed/main.c create mode 100644 packages/Python/lldbsuite/test/lang/objc/.categories create mode 100644 packages/Python/lldbsuite/test/lang/objc/bitfield_ivars/TestBitfieldIvars.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/bitfield_ivars/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/blocks/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/blocks/TestObjCIvarsInBlocks.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/blocks/ivars-in-blocks.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/blocks/ivars-in-blocks.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/blocks/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/Test/Foo.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/Test/Test.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/Test/Test.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/TestConflictingDefinition.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/TestExt/Foo.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/TestExt/TestExt.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/TestExt/TestExt.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/conflicting-definition/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/forward-decl/Container.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/forward-decl/Container.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/forward-decl/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/forward-decl/TestForwardDecl.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/forward-decl/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestConstStrings.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestFoundationDisassembly.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestObjCMethods.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestObjCMethods2.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestObjectDescriptionAPI.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestRuntimeTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/TestSymbolTable.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/const-strings.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/my-base.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/foundation/my-base.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/global_ptrs/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/global_ptrs/TestGlobalObjects.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/global_ptrs/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/hidden-ivars/InternalDefiner.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/hidden-ivars/InternalDefiner.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/hidden-ivars/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/hidden-ivars/TestHiddenIvars.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/hidden-ivars/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/ivar-IMP/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/ivar-IMP/TestObjCiVarIMP.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/ivar-IMP/myclass.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/ivar-IMP/myclass.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/ivar-IMP/repro.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-auto-import/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-auto-import/TestModulesAutoImport.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-auto-import/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-incomplete/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-incomplete/TestIncompleteModules.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-incomplete/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-incomplete/module.map create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-incomplete/myModule.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-incomplete/myModule.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-inline-functions/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-inline-functions/TestModulesInlineFunctions.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-inline-functions/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-inline-functions/module.map create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-inline-functions/myModule.c create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules-inline-functions/myModule.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules/TestObjCModules.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/modules/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc++/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc++/TestObjCXX.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc++/main.mm create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-baseclass-sbtype/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-baseclass-sbtype/TestObjCBaseClassSBType.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-baseclass-sbtype/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-builtin-types/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-builtin-types/TestObjCBuiltinTypes.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-builtin-types/main.cpp create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-checker/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-checker/TestObjCCheckers.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-checker/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-class-method/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-class-method/TestObjCClassMethod.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-class-method/class.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dyn-sbtype/.categories create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dyn-sbtype/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dyn-sbtype/TestObjCDynamicSBType.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dyn-sbtype/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dynamic-value/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-dynamic-value/dynamic-value.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-offsets/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-offsets/TestObjCIvarOffsets.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-offsets/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-offsets/objc-ivar-offsets.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-protocols/TestIvarProtocols.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-protocols/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-stripped/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-stripped/TestObjCIvarStripped.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-ivar-stripped/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-optimized/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-optimized/TestObjcOptimized.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-optimized/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-property/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-property/TestObjCProperty.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-property/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-runtime-ivars/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-runtime-ivars/TestRuntimeIvars.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-runtime-ivars/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-static-method-stripped/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-static-method-stripped/TestObjCStaticMethodStripped.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-static-method-stripped/static.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-static-method/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-static-method/TestObjCStaticMethod.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-static-method/static.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-stepping/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-stepping/TestObjCStepping.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-stepping/stepping-tests.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-struct-argument/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-struct-argument/TestObjCStructArgument.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-struct-argument/test.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-struct-return/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-struct-return/TestObjCStructReturn.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-struct-return/test.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-super/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-super/TestObjCSuper.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/objc-super/class.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/print-obj/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/print-obj/TestPrintObj.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/print-obj/blocked.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/ptr_refs/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/ptr_refs/TestPtrRefsObjC.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/ptr_refs/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/radar-9691614/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/radar-9691614/TestObjCMethodReturningBOOL.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/radar-9691614/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-10967107/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-10967107/TestRdar10967107.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-10967107/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-11355592/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-11355592/TestRdar11355592.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-11355592/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-12408181/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-12408181/TestRdar12408181.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/rdar-12408181/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/Bar.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/Bar.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/Foo.h create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/Foo.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/TestRealDefinition.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/real-definition/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/sample/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/sample/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/self/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/self/TestObjCSelf.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/self/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/single-entry-dictionary/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objc/single-entry-dictionary/TestObjCSingleEntryDictionary.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/single-entry-dictionary/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/unicode-string/TestUnicodeString.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/unicode-string/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objc/variadic_methods/TestVariadicMethods.py create mode 100644 packages/Python/lldbsuite/test/lang/objc/variadic_methods/main.m create mode 100644 packages/Python/lldbsuite/test/lang/objcxx/objcxx-ivar-vector/TestIvarVector.py create mode 100644 packages/Python/lldbsuite/test/lang/objcxx/objcxx-ivar-vector/main.mm create mode 100644 packages/Python/lldbsuite/test/lang/objcxx/sample/Makefile create mode 100644 packages/Python/lldbsuite/test/lang/objcxx/sample/main.mm create mode 100644 packages/Python/lldbsuite/test/linux/builtin_trap/Makefile create mode 100644 packages/Python/lldbsuite/test/linux/builtin_trap/TestBuiltinTrap.py create mode 100644 packages/Python/lldbsuite/test/linux/builtin_trap/main.cpp create mode 100644 packages/Python/lldbsuite/test/linux/thread/create_during_instruction_step/Makefile create mode 100644 packages/Python/lldbsuite/test/linux/thread/create_during_instruction_step/TestCreateDuringInstructionStep.py create mode 100644 packages/Python/lldbsuite/test/linux/thread/create_during_instruction_step/main.cpp create mode 100644 packages/Python/lldbsuite/test/lldb_pylint_helper.py create mode 100644 packages/Python/lldbsuite/test/lldbbench.py create mode 100644 packages/Python/lldbsuite/test/lldbcurses.py create mode 100644 packages/Python/lldbsuite/test/lldbdwarf.py create mode 100644 packages/Python/lldbsuite/test/lldbinline.py create mode 100644 packages/Python/lldbsuite/test/lldbpexpect.py create mode 100644 packages/Python/lldbsuite/test/lldbplatform.py create mode 100644 packages/Python/lldbsuite/test/lldbplatformutil.py create mode 100644 packages/Python/lldbsuite/test/lldbtest.py create mode 100644 packages/Python/lldbsuite/test/lldbtest_config.py create mode 100644 packages/Python/lldbsuite/test/lldbutil.py create mode 100644 packages/Python/lldbsuite/test/lock.py create mode 100644 packages/Python/lldbsuite/test/logging/Makefile create mode 100644 packages/Python/lldbsuite/test/logging/TestLogging.py create mode 100644 packages/Python/lldbsuite/test/logging/main.cpp create mode 100644 packages/Python/lldbsuite/test/macosx/add-dsym/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/add-dsym/TestAddDsymMidExecutionCommand.py create mode 100644 packages/Python/lldbsuite/test/macosx/add-dsym/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/debug-info/apple_types/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/debug-info/apple_types/TestAppleTypesIsProduced.py create mode 100644 packages/Python/lldbsuite/test/macosx/debug-info/apple_types/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/TestBundleWithDotInFilename.py create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/bundle.c create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/bundle-with-dot-in-filename/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Info.plist create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/MyFramework.h create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/TestDeepBundle.py create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/find-dsym/deep-bundle/myframework.c create mode 100644 packages/Python/lldbsuite/test/macosx/indirect_symbol/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/indirect_symbol/TestIndirectSymbols.py create mode 100644 packages/Python/lldbsuite/test/macosx/indirect_symbol/alias.list create mode 100644 packages/Python/lldbsuite/test/macosx/indirect_symbol/indirect.c create mode 100644 packages/Python/lldbsuite/test/macosx/indirect_symbol/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/indirect_symbol/reexport.c create mode 100644 packages/Python/lldbsuite/test/macosx/nslog/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/nslog/TestDarwinNSLogOutput.py create mode 100644 packages/Python/lldbsuite/test/macosx/nslog/main.m create mode 100644 packages/Python/lldbsuite/test/macosx/order/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/order/TestOrderFile.py create mode 100644 packages/Python/lldbsuite/test/macosx/order/cmds.txt create mode 100644 packages/Python/lldbsuite/test/macosx/order/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/order/order-file create mode 100644 packages/Python/lldbsuite/test/macosx/queues/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/queues/TestQueues.py create mode 100644 packages/Python/lldbsuite/test/macosx/queues/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/safe-to-func-call/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/safe-to-func-call/TestSafeFuncCalls.py create mode 100644 packages/Python/lldbsuite/test/macosx/safe-to-func-call/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/thread-names/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/thread-names/TestInterruptThreadNames.py create mode 100644 packages/Python/lldbsuite/test/macosx/thread-names/main.c create mode 100644 packages/Python/lldbsuite/test/macosx/universal/Makefile create mode 100644 packages/Python/lldbsuite/test/macosx/universal/TestUniversal.py create mode 100644 packages/Python/lldbsuite/test/macosx/universal/main.c create mode 100644 packages/Python/lldbsuite/test/make/Android.rules create mode 100644 packages/Python/lldbsuite/test/make/Makefile.rules create mode 100644 packages/Python/lldbsuite/test/make/pseudo_barrier.h create mode 100644 packages/Python/lldbsuite/test/make/test_common.h create mode 100644 packages/Python/lldbsuite/test/plugins/builder_base.py create mode 100644 packages/Python/lldbsuite/test/plugins/builder_darwin.py create mode 100644 packages/Python/lldbsuite/test/plugins/builder_freebsd.py create mode 100644 packages/Python/lldbsuite/test/plugins/builder_linux.py create mode 100644 packages/Python/lldbsuite/test/plugins/builder_netbsd.py create mode 100644 packages/Python/lldbsuite/test/plugins/builder_win32.py create mode 100644 packages/Python/lldbsuite/test/python_api/.categories create mode 100644 packages/Python/lldbsuite/test/python_api/breakpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/breakpoint/TestBreakpointAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/breakpoint/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/class_members/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/class_members/TestSBTypeClassMembers.py create mode 100644 packages/Python/lldbsuite/test/python_api/class_members/main.mm create mode 100644 packages/Python/lldbsuite/test/python_api/debugger/TestDebuggerAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_address.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_block.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_breakpoint.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_breakpointlocation.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_broadcaster.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_communication.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_compileunit.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_debugger.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_error.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_event.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_filespec.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_frame.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_function.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_instruction.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_instructionlist.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_lineentry.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_listener.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_module.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_process.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_section.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_stringlist.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_symbol.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_symbolcontext.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_target.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_thread.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_type.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_value.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_valuelist.py create mode 100644 packages/Python/lldbsuite/test/python_api/default-constructor/sb_watchpoint.py create mode 100644 packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassembleRawData.py create mode 100644 packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassemble_VST1_64.py create mode 100644 packages/Python/lldbsuite/test/python_api/event/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/event/TestEvents.py create mode 100644 packages/Python/lldbsuite/test/python_api/event/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/exprpath_synthetic/TestExprPathSynthetic.py create mode 100644 packages/Python/lldbsuite/test/python_api/exprpath_synthetic/main.mm create mode 100644 packages/Python/lldbsuite/test/python_api/findvalue_duplist/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/findvalue_duplist/TestSBFrameFindValue.py create mode 100644 packages/Python/lldbsuite/test/python_api/findvalue_duplist/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/formatters/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/formatters/TestFormattersSBAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/formatters/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/formatters/synth.py create mode 100644 packages/Python/lldbsuite/test/python_api/frame/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/frame/TestFrames.py create mode 100644 packages/Python/lldbsuite/test/python_api/frame/get-variables/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/frame/get-variables/TestGetVariables.py create mode 100644 packages/Python/lldbsuite/test/python_api/frame/get-variables/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/frame/inlines/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/frame/inlines/TestInlinedFrame.py create mode 100644 packages/Python/lldbsuite/test/python_api/frame/inlines/inlines.c create mode 100644 packages/Python/lldbsuite/test/python_api/frame/inlines/inlines.h create mode 100644 packages/Python/lldbsuite/test/python_api/frame/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/function_symbol/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/function_symbol/TestDisasmAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/function_symbol/TestSymbolAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/function_symbol/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/hello_world/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/hello_world/TestHelloWorld.py create mode 100644 packages/Python/lldbsuite/test/python_api/hello_world/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/interpreter/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/interpreter/TestCommandInterpreterAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/interpreter/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/frame/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/frame/TestFrameUtils.py create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/frame/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/iter/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/iter/TestLLDBIterator.py create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/iter/TestRegistersIterator.py create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/iter/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/process/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/process/TestPrintStackTraces.py create mode 100644 packages/Python/lldbsuite/test/python_api/lldbutil/process/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/module_section/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py create mode 100644 packages/Python/lldbsuite/test/python_api/module_section/b.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/module_section/c.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/module_section/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/name_lookup/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/name_lookup/TestNameLookup.py create mode 100644 packages/Python/lldbsuite/test/python_api/name_lookup/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/objc_type/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/objc_type/TestObjCType.py create mode 100644 packages/Python/lldbsuite/test/python_api/objc_type/main.m create mode 100644 packages/Python/lldbsuite/test/python_api/process/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/process/TestProcessAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/process/io/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/process/io/TestProcessIO.py create mode 100644 packages/Python/lldbsuite/test/python_api/process/io/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/process/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/rdar-12481949/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/rdar-12481949/Test-rdar-12481949.py create mode 100644 packages/Python/lldbsuite/test/python_api/rdar-12481949/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/sbdata/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/sbdata/TestSBData.py create mode 100644 packages/Python/lldbsuite/test/python_api/sbdata/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/sbstructureddata/TestStructuredDataAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/sbtype_typeclass/TestSBTypeTypeClass.py create mode 100644 packages/Python/lldbsuite/test/python_api/sbtype_typeclass/main.m create mode 100644 packages/Python/lldbsuite/test/python_api/sbvalue_const_addrof/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/sbvalue_const_addrof/TestSBValueConstAddrOf.py create mode 100644 packages/Python/lldbsuite/test/python_api/sbvalue_const_addrof/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/sbvalue_persist/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/sbvalue_persist/TestSBValuePersist.py create mode 100644 packages/Python/lldbsuite/test/python_api/sbvalue_persist/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/section/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/section/TestSectionAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/section/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/signals/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/signals/TestSignalsAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/signals/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/TestSymbolContext.py create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/two-files/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/two-files/TestSymbolContextTwoFiles.py create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/two-files/decls.h create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/two-files/file1.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/symbol-context/two-files/file2.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/target/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/target/TestTargetAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/target/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/thread/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/thread/TestThreadAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/thread/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/thread/main2.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/type/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/type/TestTypeList.py create mode 100644 packages/Python/lldbsuite/test/python_api/type/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/value/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/value/TestValueAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/value/change_values/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/value/change_values/TestChangeValueAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/value/change_values/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/value/empty_class/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/value/empty_class/TestValueAPIEmptyClass.py create mode 100644 packages/Python/lldbsuite/test/python_api/value/empty_class/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/value/linked_list/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py create mode 100644 packages/Python/lldbsuite/test/python_api/value/linked_list/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/value/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/value_var_update/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/value_var_update/TestValueVarUpdate.py create mode 100644 packages/Python/lldbsuite/test/python_api/value_var_update/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/TestSetWatchpoint.py create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIgnoreCount.py create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/TestWatchpointIter.py create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/condition/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/condition/main.cpp create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/main.c create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/Makefile create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestSetWatchlocation.py create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py create mode 100644 packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/main.cpp create mode 100644 packages/Python/lldbsuite/test/redo.py create mode 100644 packages/Python/lldbsuite/test/sample_test/Makefile create mode 100644 packages/Python/lldbsuite/test/sample_test/TestSampleInlineTest.py create mode 100644 packages/Python/lldbsuite/test/sample_test/TestSampleTest.py create mode 100644 packages/Python/lldbsuite/test/sample_test/main.c create mode 100644 packages/Python/lldbsuite/test/settings/Makefile create mode 100644 packages/Python/lldbsuite/test/settings/TestSettings.py create mode 100644 packages/Python/lldbsuite/test/settings/main.cpp create mode 100644 packages/Python/lldbsuite/test/settings/quoting/Makefile create mode 100644 packages/Python/lldbsuite/test/settings/quoting/TestQuoting.py create mode 100644 packages/Python/lldbsuite/test/settings/quoting/main.c create mode 100644 packages/Python/lldbsuite/test/source-manager/Makefile create mode 100644 packages/Python/lldbsuite/test/source-manager/TestSourceManager.py create mode 100644 packages/Python/lldbsuite/test/source-manager/hidden/.keep create mode 100644 packages/Python/lldbsuite/test/source-manager/main.c create mode 100644 packages/Python/lldbsuite/test/terminal/TestSTTYBeforeAndAfter.py create mode 100644 packages/Python/lldbsuite/test/test_categories.py create mode 100644 packages/Python/lldbsuite/test/test_result.py create mode 100644 packages/Python/lldbsuite/test/test_runner/README.txt create mode 100644 packages/Python/lldbsuite/test/test_runner/__init__.py create mode 100644 packages/Python/lldbsuite/test/test_runner/process_control.py create mode 100644 packages/Python/lldbsuite/test/test_runner/test/__init__.py create mode 100755 packages/Python/lldbsuite/test/test_runner/test/inferior.py create mode 100755 packages/Python/lldbsuite/test/test_runner/test/test_process_control.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/TestMiEnvironmentCd.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/TestMiExit.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/TestMiFile.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/TestMiGdbSetShow.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/TestMiLibraryLoaded.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/TestMiPrompt.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/TestMiBreak.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/breakpoint/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/control/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/control/TestMiExec.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/control/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/data/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/data/TestMiData.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/data/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiCliSupport.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/TestMiInterpreterExec.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/interpreter/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/lexical_scope/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/lexical_scope/TestMiLexicalScope.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/lexical_scope/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/lldbmi_testcase.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/signal/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/signal/TestMiSignal.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/signal/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/stack/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/stack/TestMiStack.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/stack/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/TestMiStartupOptions.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_error create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/startup_options/start_script_exit create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/syntax/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/syntax/TestMiSyntax.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/syntax/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/target/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/target/TestMiTarget.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/target/test_attach.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/threadinfo/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/threadinfo/TestMiThreadInfo.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/threadinfo/test_threadinfo.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/variable/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiGdbSetShowPrint.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/variable/TestMiVar.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-mi/variable/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/.clang-format create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAttach.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteAuxvSupport.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteExpeditedRegisters.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteHostInfo.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteKill.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteModuleInfo.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteProcessInfo.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteRegisterState.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteSingleStep.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemoteThreadsInStopReply.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_qThreadStopInfo.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestGdbRemote_vCont.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/TestLldbGdbServer.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubReverseConnect.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/commandline/TestStubSetSID.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/exit-code/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/exit-code/TestGdbRemoteExitCode.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/exit-code/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteAbort.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/TestGdbRemoteSegFault.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/inferior-crash/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/signal-filtering/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/signal-filtering/TestGdbRemote_QPassSignals.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/signal-filtering/main.cpp create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/socket_packet_pump.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/test/test_lldbgdbserverutils.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/thread-name/Makefile create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/thread-name/TestGdbRemoteThreadName.py create mode 100644 packages/Python/lldbsuite/test/tools/lldb-server/thread-name/main.cpp create mode 100644 packages/Python/lldbsuite/test/types/AbstractBase.py create mode 100644 packages/Python/lldbsuite/test/types/HideTestFailures.py create mode 100644 packages/Python/lldbsuite/test/types/Makefile create mode 100644 packages/Python/lldbsuite/test/types/TestFloatTypes.py create mode 100644 packages/Python/lldbsuite/test/types/TestFloatTypesExpr.py create mode 100644 packages/Python/lldbsuite/test/types/TestIntegerTypes.py create mode 100644 packages/Python/lldbsuite/test/types/TestIntegerTypesExpr.py create mode 100644 packages/Python/lldbsuite/test/types/TestRecursiveTypes.py create mode 100644 packages/Python/lldbsuite/test/types/basic_type.cpp create mode 100644 packages/Python/lldbsuite/test/types/char.cpp create mode 100644 packages/Python/lldbsuite/test/types/double.cpp create mode 100644 packages/Python/lldbsuite/test/types/float.cpp create mode 100644 packages/Python/lldbsuite/test/types/int.cpp create mode 100644 packages/Python/lldbsuite/test/types/long.cpp create mode 100644 packages/Python/lldbsuite/test/types/long_long.cpp create mode 100644 packages/Python/lldbsuite/test/types/recursive_type_1.cpp create mode 100644 packages/Python/lldbsuite/test/types/recursive_type_2.cpp create mode 100644 packages/Python/lldbsuite/test/types/recursive_type_main.cpp create mode 100644 packages/Python/lldbsuite/test/types/short.cpp create mode 100644 packages/Python/lldbsuite/test/types/unsigned_char.cpp create mode 100644 packages/Python/lldbsuite/test/types/unsigned_int.cpp create mode 100644 packages/Python/lldbsuite/test/types/unsigned_long.cpp create mode 100644 packages/Python/lldbsuite/test/types/unsigned_long_long.cpp create mode 100644 packages/Python/lldbsuite/test/types/unsigned_short.cpp create mode 100644 packages/Python/lldbsuite/test/warnings/uuid/Makefile create mode 100644 packages/Python/lldbsuite/test/warnings/uuid/TestAddDsymCommand.py create mode 100644 packages/Python/lldbsuite/test/warnings/uuid/main.cpp.template create mode 100644 packages/Python/lldbsuite/test_event/__init__.py create mode 100644 packages/Python/lldbsuite/test_event/build_exception.py create mode 100644 packages/Python/lldbsuite/test_event/dotest_channels.py create mode 100644 packages/Python/lldbsuite/test_event/event_builder.py create mode 100644 packages/Python/lldbsuite/test_event/formatter/__init__.py create mode 100644 packages/Python/lldbsuite/test_event/formatter/curses.py create mode 100644 packages/Python/lldbsuite/test_event/formatter/dump_formatter.py create mode 100644 packages/Python/lldbsuite/test_event/formatter/pickled.py create mode 100644 packages/Python/lldbsuite/test_event/formatter/results_formatter.py create mode 100644 packages/Python/lldbsuite/test_event/formatter/xunit.py create mode 100644 packages/Python/lldbsuite/test_event/test/resources/invalid_decorator/TestInvalidDecorator.py create mode 100644 packages/Python/lldbsuite/test_event/test/src/TestCatchInvalidDecorator.py create mode 100644 packages/Python/lldbsuite/test_event/test/src/event_collector.py create mode 100644 resources/LLDB-Info.plist create mode 100644 scripts/CMakeLists.txt create mode 100644 scripts/Python/android/host_art_bt.py create mode 100755 scripts/Python/finish-swig-Python-LLDB.sh create mode 100644 scripts/Python/finishSwigPythonLLDB.py create mode 100644 scripts/Python/modify-python-lldb.py create mode 100644 scripts/Python/modules/CMakeLists.txt create mode 100644 scripts/Python/modules/readline/CMakeLists.txt create mode 100644 scripts/Python/modules/readline/readline.cpp create mode 100644 scripts/Python/prepare_binding_Python.py create mode 100644 scripts/Python/python-extensions.swig create mode 100644 scripts/Python/python-swigsafecast.swig create mode 100644 scripts/Python/python-typemaps.swig create mode 100644 scripts/Python/python-wrapper.swig create mode 100755 scripts/Python/remote-build.py create mode 100644 scripts/Python/use_lldb_suite.py create mode 100755 scripts/Xcode/build-llvm.py create mode 100644 scripts/Xcode/lldbbuild.py create mode 100644 scripts/Xcode/package-clang-headers.py create mode 100755 scripts/Xcode/prepare-gtest-run-dir.sh create mode 100644 scripts/Xcode/repo.py create mode 100644 scripts/Xcode/repos/FALLBACK create mode 100644 scripts/Xcode/repos/svn-trunk.json create mode 100755 scripts/analyze-project-deps.py create mode 100755 scripts/build-lldb-llvm-clang create mode 100755 scripts/buildbot.py create mode 100755 scripts/checkpoint-llvm.pl create mode 100755 scripts/disasm-gdb-remote.pl create mode 100755 scripts/finish-swig-wrapper-classes.sh create mode 100644 scripts/finishSwigWrapperClasses.py create mode 100755 scripts/generate-vers.pl create mode 100644 scripts/get_relative_lib_dir.py create mode 100755 scripts/install-lldb.sh create mode 100644 scripts/install_custom_python.py create mode 100644 scripts/interface/SBAddress.i create mode 100644 scripts/interface/SBAttachInfo.i create mode 100644 scripts/interface/SBBlock.i create mode 100644 scripts/interface/SBBreakpoint.i create mode 100644 scripts/interface/SBBreakpointLocation.i create mode 100644 scripts/interface/SBBroadcaster.i create mode 100644 scripts/interface/SBCommandInterpreter.i create mode 100644 scripts/interface/SBCommandReturnObject.i create mode 100644 scripts/interface/SBCommunication.i create mode 100644 scripts/interface/SBCompileUnit.i create mode 100644 scripts/interface/SBData.i create mode 100644 scripts/interface/SBDebugger.i create mode 100644 scripts/interface/SBDeclaration.i create mode 100644 scripts/interface/SBError.i create mode 100644 scripts/interface/SBEvent.i create mode 100644 scripts/interface/SBExecutionContext.i create mode 100644 scripts/interface/SBExpressionOptions.i create mode 100644 scripts/interface/SBFileSpec.i create mode 100644 scripts/interface/SBFileSpecList.i create mode 100644 scripts/interface/SBFrame.i create mode 100644 scripts/interface/SBFunction.i create mode 100644 scripts/interface/SBHostOS.i create mode 100644 scripts/interface/SBInstruction.i create mode 100644 scripts/interface/SBInstructionList.i create mode 100644 scripts/interface/SBLanguageRuntime.i create mode 100644 scripts/interface/SBLaunchInfo.i create mode 100644 scripts/interface/SBLineEntry.i create mode 100644 scripts/interface/SBListener.i create mode 100644 scripts/interface/SBMemoryRegionInfo.i create mode 100644 scripts/interface/SBMemoryRegionInfoList.i create mode 100644 scripts/interface/SBModule.i create mode 100644 scripts/interface/SBModuleSpec.i create mode 100644 scripts/interface/SBPlatform.i create mode 100644 scripts/interface/SBProcess.i create mode 100644 scripts/interface/SBQueue.i create mode 100644 scripts/interface/SBQueueItem.i create mode 100644 scripts/interface/SBSection.i create mode 100644 scripts/interface/SBSourceManager.i create mode 100644 scripts/interface/SBStream.i create mode 100644 scripts/interface/SBStringList.i create mode 100644 scripts/interface/SBStructuredData.i create mode 100644 scripts/interface/SBSymbol.i create mode 100644 scripts/interface/SBSymbolContext.i create mode 100644 scripts/interface/SBSymbolContextList.i create mode 100644 scripts/interface/SBTarget.i create mode 100644 scripts/interface/SBThread.i create mode 100644 scripts/interface/SBThreadCollection.i create mode 100644 scripts/interface/SBThreadPlan.i create mode 100644 scripts/interface/SBTrace.i create mode 100644 scripts/interface/SBTraceOptions.i create mode 100644 scripts/interface/SBType.i create mode 100644 scripts/interface/SBTypeCategory.i create mode 100644 scripts/interface/SBTypeEnumMember.i create mode 100644 scripts/interface/SBTypeFilter.i create mode 100644 scripts/interface/SBTypeFormat.i create mode 100644 scripts/interface/SBTypeNameSpecifier.i create mode 100644 scripts/interface/SBTypeSummary.i create mode 100644 scripts/interface/SBTypeSynthetic.i create mode 100644 scripts/interface/SBUnixSignals.i create mode 100644 scripts/interface/SBValue.i create mode 100644 scripts/interface/SBValueList.i create mode 100644 scripts/interface/SBVariablesOptions.i create mode 100644 scripts/interface/SBWatchpoint.i create mode 100644 scripts/lldb.swig create mode 100755 scripts/prepare_bindings.py create mode 100755 scripts/sed-sources create mode 100755 scripts/shush create mode 100644 scripts/swig_bot.py create mode 100644 scripts/swig_bot_lib/__init__.py create mode 100644 scripts/swig_bot_lib/client.py create mode 100644 scripts/swig_bot_lib/local.py create mode 100644 scripts/swig_bot_lib/remote.py create mode 100644 scripts/swig_bot_lib/server.py create mode 100644 scripts/use_lldb_suite.py create mode 100644 scripts/utilsArgsParse.py create mode 100644 scripts/utilsDebug.py create mode 100644 scripts/utilsOsType.py create mode 100755 scripts/verify_api.py create mode 100644 source/API/CMakeLists.txt create mode 100644 source/API/SBAddress.cpp create mode 100644 source/API/SBAttachInfo.cpp create mode 100644 source/API/SBBlock.cpp create mode 100644 source/API/SBBreakpoint.cpp create mode 100644 source/API/SBBreakpointLocation.cpp create mode 100644 source/API/SBBroadcaster.cpp create mode 100644 source/API/SBCommandInterpreter.cpp create mode 100644 source/API/SBCommandReturnObject.cpp create mode 100644 source/API/SBCommunication.cpp create mode 100644 source/API/SBCompileUnit.cpp create mode 100644 source/API/SBData.cpp create mode 100644 source/API/SBDebugger.cpp create mode 100644 source/API/SBDeclaration.cpp create mode 100644 source/API/SBError.cpp create mode 100644 source/API/SBEvent.cpp create mode 100644 source/API/SBExecutionContext.cpp create mode 100644 source/API/SBExpressionOptions.cpp create mode 100644 source/API/SBFileSpec.cpp create mode 100644 source/API/SBFileSpecList.cpp create mode 100644 source/API/SBFrame.cpp create mode 100644 source/API/SBFunction.cpp create mode 100644 source/API/SBHostOS.cpp create mode 100644 source/API/SBInstruction.cpp create mode 100644 source/API/SBInstructionList.cpp create mode 100644 source/API/SBLanguageRuntime.cpp create mode 100644 source/API/SBLaunchInfo.cpp create mode 100644 source/API/SBLineEntry.cpp create mode 100644 source/API/SBListener.cpp create mode 100644 source/API/SBMemoryRegionInfo.cpp create mode 100644 source/API/SBMemoryRegionInfoList.cpp create mode 100644 source/API/SBModule.cpp create mode 100644 source/API/SBModuleSpec.cpp create mode 100644 source/API/SBPlatform.cpp create mode 100644 source/API/SBProcess.cpp create mode 100644 source/API/SBQueue.cpp create mode 100644 source/API/SBQueueItem.cpp create mode 100644 source/API/SBSection.cpp create mode 100644 source/API/SBSourceManager.cpp create mode 100644 source/API/SBStream.cpp create mode 100644 source/API/SBStringList.cpp create mode 100644 source/API/SBStructuredData.cpp create mode 100644 source/API/SBSymbol.cpp create mode 100644 source/API/SBSymbolContext.cpp create mode 100644 source/API/SBSymbolContextList.cpp create mode 100644 source/API/SBTarget.cpp create mode 100644 source/API/SBThread.cpp create mode 100644 source/API/SBThreadCollection.cpp create mode 100644 source/API/SBThreadPlan.cpp create mode 100644 source/API/SBTrace.cpp create mode 100644 source/API/SBTraceOptions.cpp create mode 100644 source/API/SBType.cpp create mode 100644 source/API/SBTypeCategory.cpp create mode 100644 source/API/SBTypeEnumMember.cpp create mode 100644 source/API/SBTypeFilter.cpp create mode 100644 source/API/SBTypeFormat.cpp create mode 100644 source/API/SBTypeNameSpecifier.cpp create mode 100644 source/API/SBTypeSummary.cpp create mode 100644 source/API/SBTypeSynthetic.cpp create mode 100644 source/API/SBUnixSignals.cpp create mode 100644 source/API/SBValue.cpp create mode 100644 source/API/SBValueList.cpp create mode 100644 source/API/SBVariablesOptions.cpp create mode 100644 source/API/SBWatchpoint.cpp create mode 100644 source/API/SystemInitializerFull.cpp create mode 100644 source/API/liblldb-private.exports create mode 100644 source/API/liblldb.exports create mode 100644 source/API/liblldb.xcode.exports create mode 100644 source/Breakpoint/Breakpoint.cpp create mode 100644 source/Breakpoint/BreakpointID.cpp create mode 100644 source/Breakpoint/BreakpointIDList.cpp create mode 100644 source/Breakpoint/BreakpointList.cpp create mode 100644 source/Breakpoint/BreakpointLocation.cpp create mode 100644 source/Breakpoint/BreakpointLocationCollection.cpp create mode 100644 source/Breakpoint/BreakpointLocationList.cpp create mode 100644 source/Breakpoint/BreakpointOptions.cpp create mode 100644 source/Breakpoint/BreakpointResolver.cpp create mode 100644 source/Breakpoint/BreakpointResolverAddress.cpp create mode 100644 source/Breakpoint/BreakpointResolverFileLine.cpp create mode 100644 source/Breakpoint/BreakpointResolverFileRegex.cpp create mode 100644 source/Breakpoint/BreakpointResolverName.cpp create mode 100644 source/Breakpoint/BreakpointSite.cpp create mode 100644 source/Breakpoint/BreakpointSiteList.cpp create mode 100644 source/Breakpoint/CMakeLists.txt create mode 100644 source/Breakpoint/Stoppoint.cpp create mode 100644 source/Breakpoint/StoppointCallbackContext.cpp create mode 100644 source/Breakpoint/StoppointLocation.cpp create mode 100644 source/Breakpoint/Watchpoint.cpp create mode 100644 source/Breakpoint/WatchpointList.cpp create mode 100644 source/Breakpoint/WatchpointOptions.cpp create mode 100644 source/CMakeLists.txt create mode 100644 source/Commands/CMakeLists.txt create mode 100644 source/Commands/CommandCompletions.cpp create mode 100644 source/Commands/CommandObjectApropos.cpp create mode 100644 source/Commands/CommandObjectApropos.h create mode 100644 source/Commands/CommandObjectArgs.cpp create mode 100644 source/Commands/CommandObjectArgs.h create mode 100644 source/Commands/CommandObjectBreakpoint.cpp create mode 100644 source/Commands/CommandObjectBreakpoint.h create mode 100644 source/Commands/CommandObjectBreakpointCommand.cpp create mode 100644 source/Commands/CommandObjectBreakpointCommand.h create mode 100644 source/Commands/CommandObjectBugreport.cpp create mode 100644 source/Commands/CommandObjectBugreport.h create mode 100644 source/Commands/CommandObjectCommands.cpp create mode 100644 source/Commands/CommandObjectCommands.h create mode 100644 source/Commands/CommandObjectDisassemble.cpp create mode 100644 source/Commands/CommandObjectDisassemble.h create mode 100644 source/Commands/CommandObjectExpression.cpp create mode 100644 source/Commands/CommandObjectExpression.h create mode 100644 source/Commands/CommandObjectFrame.cpp create mode 100644 source/Commands/CommandObjectFrame.h create mode 100644 source/Commands/CommandObjectGUI.cpp create mode 100644 source/Commands/CommandObjectGUI.h create mode 100644 source/Commands/CommandObjectHelp.cpp create mode 100644 source/Commands/CommandObjectHelp.h create mode 100644 source/Commands/CommandObjectLanguage.cpp create mode 100644 source/Commands/CommandObjectLanguage.h create mode 100644 source/Commands/CommandObjectLog.cpp create mode 100644 source/Commands/CommandObjectLog.h create mode 100644 source/Commands/CommandObjectMemory.cpp create mode 100644 source/Commands/CommandObjectMemory.h create mode 100644 source/Commands/CommandObjectMultiword.cpp create mode 100644 source/Commands/CommandObjectPlatform.cpp create mode 100644 source/Commands/CommandObjectPlatform.h create mode 100644 source/Commands/CommandObjectPlugin.cpp create mode 100644 source/Commands/CommandObjectPlugin.h create mode 100644 source/Commands/CommandObjectProcess.cpp create mode 100644 source/Commands/CommandObjectProcess.h create mode 100644 source/Commands/CommandObjectQuit.cpp create mode 100644 source/Commands/CommandObjectQuit.h create mode 100644 source/Commands/CommandObjectRegister.cpp create mode 100644 source/Commands/CommandObjectRegister.h create mode 100644 source/Commands/CommandObjectSettings.cpp create mode 100644 source/Commands/CommandObjectSettings.h create mode 100644 source/Commands/CommandObjectSource.cpp create mode 100644 source/Commands/CommandObjectSource.h create mode 100644 source/Commands/CommandObjectSyntax.cpp create mode 100644 source/Commands/CommandObjectSyntax.h create mode 100644 source/Commands/CommandObjectTarget.cpp create mode 100644 source/Commands/CommandObjectTarget.h create mode 100644 source/Commands/CommandObjectThread.cpp create mode 100644 source/Commands/CommandObjectThread.h create mode 100644 source/Commands/CommandObjectType.cpp create mode 100644 source/Commands/CommandObjectType.h create mode 100644 source/Commands/CommandObjectVersion.cpp create mode 100644 source/Commands/CommandObjectVersion.h create mode 100644 source/Commands/CommandObjectWatchpoint.cpp create mode 100644 source/Commands/CommandObjectWatchpoint.h create mode 100644 source/Commands/CommandObjectWatchpointCommand.cpp create mode 100644 source/Commands/CommandObjectWatchpointCommand.h create mode 100644 source/Core/Address.cpp create mode 100644 source/Core/AddressRange.cpp create mode 100644 source/Core/AddressResolver.cpp create mode 100644 source/Core/AddressResolverFileLine.cpp create mode 100644 source/Core/AddressResolverName.cpp create mode 100644 source/Core/ArchSpec.cpp create mode 100644 source/Core/Broadcaster.cpp create mode 100644 source/Core/CMakeLists.txt create mode 100644 source/Core/Communication.cpp create mode 100644 source/Core/Debugger.cpp create mode 100644 source/Core/Disassembler.cpp create mode 100644 source/Core/DumpDataExtractor.cpp create mode 100644 source/Core/DynamicLoader.cpp create mode 100644 source/Core/EmulateInstruction.cpp create mode 100644 source/Core/Event.cpp create mode 100644 source/Core/FileLineResolver.cpp create mode 100644 source/Core/FileSpecList.cpp create mode 100644 source/Core/FormatEntity.cpp create mode 100644 source/Core/IOHandler.cpp create mode 100644 source/Core/Listener.cpp create mode 100644 source/Core/Mangled.cpp create mode 100644 source/Core/Module.cpp create mode 100644 source/Core/ModuleChild.cpp create mode 100644 source/Core/ModuleList.cpp create mode 100644 source/Core/Opcode.cpp create mode 100644 source/Core/PluginManager.cpp create mode 100644 source/Core/RegisterValue.cpp create mode 100644 source/Core/Scalar.cpp create mode 100644 source/Core/SearchFilter.cpp create mode 100644 source/Core/Section.cpp create mode 100644 source/Core/SourceManager.cpp create mode 100644 source/Core/State.cpp create mode 100644 source/Core/StreamAsynchronousIO.cpp create mode 100644 source/Core/StreamFile.cpp create mode 100644 source/Core/UserSettingsController.cpp create mode 100644 source/Core/Value.cpp create mode 100644 source/Core/ValueObject.cpp create mode 100644 source/Core/ValueObjectCast.cpp create mode 100644 source/Core/ValueObjectChild.cpp create mode 100644 source/Core/ValueObjectConstResult.cpp create mode 100644 source/Core/ValueObjectConstResultCast.cpp create mode 100644 source/Core/ValueObjectConstResultChild.cpp create mode 100644 source/Core/ValueObjectConstResultImpl.cpp create mode 100644 source/Core/ValueObjectDynamicValue.cpp create mode 100644 source/Core/ValueObjectList.cpp create mode 100644 source/Core/ValueObjectMemory.cpp create mode 100644 source/Core/ValueObjectRegister.cpp create mode 100644 source/Core/ValueObjectSyntheticFilter.cpp create mode 100644 source/Core/ValueObjectVariable.cpp create mode 100644 source/DataFormatters/CMakeLists.txt create mode 100644 source/DataFormatters/CXXFunctionPointer.cpp create mode 100644 source/DataFormatters/DataVisualization.cpp create mode 100644 source/DataFormatters/DumpValueObjectOptions.cpp create mode 100644 source/DataFormatters/FormatCache.cpp create mode 100644 source/DataFormatters/FormatClasses.cpp create mode 100644 source/DataFormatters/FormatManager.cpp create mode 100644 source/DataFormatters/FormattersHelpers.cpp create mode 100644 source/DataFormatters/LanguageCategory.cpp create mode 100644 source/DataFormatters/StringPrinter.cpp create mode 100644 source/DataFormatters/TypeCategory.cpp create mode 100644 source/DataFormatters/TypeCategoryMap.cpp create mode 100644 source/DataFormatters/TypeFormat.cpp create mode 100644 source/DataFormatters/TypeSummary.cpp create mode 100644 source/DataFormatters/TypeSynthetic.cpp create mode 100644 source/DataFormatters/TypeValidator.cpp create mode 100644 source/DataFormatters/ValueObjectPrinter.cpp create mode 100644 source/DataFormatters/VectorType.cpp create mode 100644 source/Expression/CMakeLists.txt create mode 100644 source/Expression/DWARFExpression.cpp create mode 100644 source/Expression/DiagnosticManager.cpp create mode 100644 source/Expression/Expression.cpp create mode 100644 source/Expression/ExpressionSourceCode.cpp create mode 100644 source/Expression/ExpressionVariable.cpp create mode 100644 source/Expression/FunctionCaller.cpp create mode 100644 source/Expression/IRDynamicChecks.cpp create mode 100644 source/Expression/IRExecutionUnit.cpp create mode 100644 source/Expression/IRInterpreter.cpp create mode 100644 source/Expression/IRMemoryMap.cpp create mode 100644 source/Expression/LLVMUserExpression.cpp create mode 100644 source/Expression/Materializer.cpp create mode 100644 source/Expression/REPL.cpp create mode 100644 source/Expression/UserExpression.cpp create mode 100644 source/Expression/UtilityFunction.cpp create mode 100644 source/Host/CMakeLists.txt create mode 100644 source/Host/android/HostInfoAndroid.cpp create mode 100644 source/Host/android/LibcGlue.cpp create mode 100644 source/Host/common/Editline.cpp create mode 100644 source/Host/common/File.cpp create mode 100644 source/Host/common/FileCache.cpp create mode 100644 source/Host/common/FileSystem.cpp create mode 100644 source/Host/common/GetOptInc.cpp create mode 100644 source/Host/common/Host.cpp create mode 100644 source/Host/common/HostInfoBase.cpp create mode 100644 source/Host/common/HostNativeThreadBase.cpp create mode 100644 source/Host/common/HostProcess.cpp create mode 100644 source/Host/common/HostThread.cpp create mode 100644 source/Host/common/LockFileBase.cpp create mode 100644 source/Host/common/MainLoop.cpp create mode 100644 source/Host/common/MonitoringProcessLauncher.cpp create mode 100644 source/Host/common/NativeBreakpoint.cpp create mode 100644 source/Host/common/NativeBreakpointList.cpp create mode 100644 source/Host/common/NativeProcessProtocol.cpp create mode 100644 source/Host/common/NativeRegisterContext.cpp create mode 100644 source/Host/common/NativeThreadProtocol.cpp create mode 100644 source/Host/common/NativeWatchpointList.cpp create mode 100644 source/Host/common/OptionParser.cpp create mode 100644 source/Host/common/PipeBase.cpp create mode 100644 source/Host/common/ProcessRunLock.cpp create mode 100644 source/Host/common/PseudoTerminal.cpp create mode 100644 source/Host/common/Socket.cpp create mode 100644 source/Host/common/SocketAddress.cpp create mode 100644 source/Host/common/SoftwareBreakpoint.cpp create mode 100644 source/Host/common/StringConvert.cpp create mode 100644 source/Host/common/Symbols.cpp create mode 100644 source/Host/common/TCPSocket.cpp create mode 100644 source/Host/common/Terminal.cpp create mode 100644 source/Host/common/ThreadLauncher.cpp create mode 100644 source/Host/common/UDPSocket.cpp create mode 100644 source/Host/common/XML.cpp create mode 100644 source/Host/freebsd/Host.cpp create mode 100644 source/Host/freebsd/HostInfoFreeBSD.cpp create mode 100644 source/Host/linux/AbstractSocket.cpp create mode 100644 source/Host/linux/Host.cpp create mode 100644 source/Host/linux/HostInfoLinux.cpp create mode 100644 source/Host/linux/LibcGlue.cpp create mode 100644 source/Host/linux/ProcessLauncherLinux.cpp create mode 100644 source/Host/linux/Support.cpp create mode 100644 source/Host/macosx/Host.mm create mode 100644 source/Host/macosx/HostInfoMacOSX.mm create mode 100644 source/Host/macosx/HostThreadMacOSX.mm create mode 100644 source/Host/macosx/Symbols.cpp create mode 100644 source/Host/macosx/cfcpp/CFCBundle.cpp create mode 100644 source/Host/macosx/cfcpp/CFCBundle.h create mode 100644 source/Host/macosx/cfcpp/CFCData.cpp create mode 100644 source/Host/macosx/cfcpp/CFCData.h create mode 100644 source/Host/macosx/cfcpp/CFCMutableArray.cpp create mode 100644 source/Host/macosx/cfcpp/CFCMutableArray.h create mode 100644 source/Host/macosx/cfcpp/CFCMutableDictionary.cpp create mode 100644 source/Host/macosx/cfcpp/CFCMutableDictionary.h create mode 100644 source/Host/macosx/cfcpp/CFCMutableSet.cpp create mode 100644 source/Host/macosx/cfcpp/CFCMutableSet.h create mode 100644 source/Host/macosx/cfcpp/CFCReleaser.h create mode 100644 source/Host/macosx/cfcpp/CFCString.cpp create mode 100644 source/Host/macosx/cfcpp/CFCString.h create mode 100644 source/Host/macosx/cfcpp/CoreFoundationCPP.h create mode 100644 source/Host/netbsd/Host.cpp create mode 100644 source/Host/netbsd/HostInfoNetBSD.cpp create mode 100644 source/Host/openbsd/Host.cpp create mode 100644 source/Host/openbsd/HostInfoOpenBSD.cpp create mode 100644 source/Host/posix/ConnectionFileDescriptorPosix.cpp create mode 100644 source/Host/posix/DomainSocket.cpp create mode 100644 source/Host/posix/FileSystem.cpp create mode 100644 source/Host/posix/HostInfoPosix.cpp create mode 100644 source/Host/posix/HostProcessPosix.cpp create mode 100644 source/Host/posix/HostThreadPosix.cpp create mode 100644 source/Host/posix/LockFilePosix.cpp create mode 100644 source/Host/posix/PipePosix.cpp create mode 100644 source/Host/posix/ProcessLauncherPosixFork.cpp create mode 100644 source/Host/windows/ConnectionGenericFileWindows.cpp create mode 100644 source/Host/windows/EditLineWin.cpp create mode 100644 source/Host/windows/FileSystem.cpp create mode 100644 source/Host/windows/Host.cpp create mode 100644 source/Host/windows/HostInfoWindows.cpp create mode 100644 source/Host/windows/HostProcessWindows.cpp create mode 100644 source/Host/windows/HostThreadWindows.cpp create mode 100644 source/Host/windows/LockFileWindows.cpp create mode 100644 source/Host/windows/PipeWindows.cpp create mode 100644 source/Host/windows/ProcessLauncherWindows.cpp create mode 100644 source/Host/windows/ProcessRunLock.cpp create mode 100644 source/Host/windows/Windows.cpp create mode 100644 source/Initialization/CMakeLists.txt create mode 100644 source/Initialization/SystemInitializer.cpp create mode 100644 source/Initialization/SystemInitializerCommon.cpp create mode 100644 source/Initialization/SystemLifetimeManager.cpp create mode 100644 source/Interpreter/Args.cpp create mode 100644 source/Interpreter/CMakeLists.txt create mode 100644 source/Interpreter/CommandAlias.cpp create mode 100644 source/Interpreter/CommandHistory.cpp create mode 100644 source/Interpreter/CommandInterpreter.cpp create mode 100644 source/Interpreter/CommandObject.cpp create mode 100644 source/Interpreter/CommandObjectRegexCommand.cpp create mode 100644 source/Interpreter/CommandObjectScript.cpp create mode 100644 source/Interpreter/CommandObjectScript.h create mode 100644 source/Interpreter/CommandOptionValidators.cpp create mode 100644 source/Interpreter/CommandReturnObject.cpp create mode 100644 source/Interpreter/OptionGroupArchitecture.cpp create mode 100644 source/Interpreter/OptionGroupBoolean.cpp create mode 100644 source/Interpreter/OptionGroupFile.cpp create mode 100644 source/Interpreter/OptionGroupFormat.cpp create mode 100644 source/Interpreter/OptionGroupOutputFile.cpp create mode 100644 source/Interpreter/OptionGroupPlatform.cpp create mode 100644 source/Interpreter/OptionGroupString.cpp create mode 100644 source/Interpreter/OptionGroupUInt64.cpp create mode 100644 source/Interpreter/OptionGroupUUID.cpp create mode 100644 source/Interpreter/OptionGroupValueObjectDisplay.cpp create mode 100644 source/Interpreter/OptionGroupVariable.cpp create mode 100644 source/Interpreter/OptionGroupWatchpoint.cpp create mode 100644 source/Interpreter/OptionValue.cpp create mode 100644 source/Interpreter/OptionValueArch.cpp create mode 100644 source/Interpreter/OptionValueArgs.cpp create mode 100644 source/Interpreter/OptionValueArray.cpp create mode 100644 source/Interpreter/OptionValueBoolean.cpp create mode 100644 source/Interpreter/OptionValueChar.cpp create mode 100644 source/Interpreter/OptionValueDictionary.cpp create mode 100644 source/Interpreter/OptionValueEnumeration.cpp create mode 100644 source/Interpreter/OptionValueFileSpec.cpp create mode 100644 source/Interpreter/OptionValueFileSpecLIst.cpp create mode 100644 source/Interpreter/OptionValueFormat.cpp create mode 100644 source/Interpreter/OptionValueFormatEntity.cpp create mode 100644 source/Interpreter/OptionValueLanguage.cpp create mode 100644 source/Interpreter/OptionValuePathMappings.cpp create mode 100644 source/Interpreter/OptionValueProperties.cpp create mode 100644 source/Interpreter/OptionValueRegex.cpp create mode 100644 source/Interpreter/OptionValueSInt64.cpp create mode 100644 source/Interpreter/OptionValueString.cpp create mode 100644 source/Interpreter/OptionValueUInt64.cpp create mode 100644 source/Interpreter/OptionValueUUID.cpp create mode 100644 source/Interpreter/Options.cpp create mode 100644 source/Interpreter/Property.cpp create mode 100644 source/Interpreter/ScriptInterpreter.cpp create mode 100644 source/Interpreter/embedded_interpreter.py create mode 100644 source/Plugins/ABI/CMakeLists.txt create mode 100644 source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp create mode 100644 source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h create mode 100644 source/Plugins/ABI/MacOSX-arm/CMakeLists.txt create mode 100644 source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.cpp create mode 100644 source/Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h create mode 100644 source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt create mode 100644 source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp create mode 100644 source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h create mode 100644 source/Plugins/ABI/MacOSX-i386/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-arm/ABISysV_arm.cpp create mode 100644 source/Plugins/ABI/SysV-arm/ABISysV_arm.h create mode 100644 source/Plugins/ABI/SysV-arm/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp create mode 100644 source/Plugins/ABI/SysV-arm64/ABISysV_arm64.h create mode 100644 source/Plugins/ABI/SysV-arm64/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp create mode 100644 source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h create mode 100644 source/Plugins/ABI/SysV-hexagon/CMakeLists.txt create mode 100755 source/Plugins/ABI/SysV-i386/ABISysV_i386.cpp create mode 100644 source/Plugins/ABI/SysV-i386/ABISysV_i386.h create mode 100644 source/Plugins/ABI/SysV-i386/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-mips/ABISysV_mips.cpp create mode 100644 source/Plugins/ABI/SysV-mips/ABISysV_mips.h create mode 100644 source/Plugins/ABI/SysV-mips/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp create mode 100644 source/Plugins/ABI/SysV-mips64/ABISysV_mips64.h create mode 100644 source/Plugins/ABI/SysV-mips64/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-ppc/ABISysV_ppc.cpp create mode 100644 source/Plugins/ABI/SysV-ppc/ABISysV_ppc.h create mode 100644 source/Plugins/ABI/SysV-ppc/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp create mode 100644 source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h create mode 100644 source/Plugins/ABI/SysV-ppc64/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-s390x/ABISysV_s390x.cpp create mode 100644 source/Plugins/ABI/SysV-s390x/ABISysV_s390x.h create mode 100644 source/Plugins/ABI/SysV-s390x/CMakeLists.txt create mode 100644 source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp create mode 100644 source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h create mode 100644 source/Plugins/ABI/SysV-x86_64/CMakeLists.txt create mode 100644 source/Plugins/CMakeLists.txt create mode 100644 source/Plugins/Disassembler/CMakeLists.txt create mode 100644 source/Plugins/Disassembler/llvm/CMakeLists.txt create mode 100644 source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp create mode 100644 source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h create mode 100644 source/Plugins/DynamicLoader/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/Darwin-Kernel/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp create mode 100644 source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h create mode 100644 source/Plugins/DynamicLoader/Hexagon-DYLD/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.cpp create mode 100644 source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h create mode 100644 source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp create mode 100644 source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp create mode 100644 source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp create mode 100644 source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h create mode 100644 source/Plugins/DynamicLoader/Static/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp create mode 100644 source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h create mode 100644 source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt create mode 100644 source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp create mode 100644 source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h create mode 100644 source/Plugins/ExpressionParser/CMakeLists.txt create mode 100644 source/Plugins/ExpressionParser/Clang/ASTDumper.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ASTDumper.h create mode 100644 source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.h create mode 100644 source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ASTStructExtractor.h create mode 100644 source/Plugins/ExpressionParser/Clang/CMakeLists.txt create mode 100644 source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangASTSource.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangUserExpression.h create mode 100644 source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h create mode 100644 source/Plugins/ExpressionParser/Clang/IRForTarget.cpp create mode 100644 source/Plugins/ExpressionParser/Clang/IRForTarget.h create mode 100644 source/Plugins/ExpressionParser/Go/CMakeLists.txt create mode 100644 source/Plugins/ExpressionParser/Go/GoAST.h create mode 100644 source/Plugins/ExpressionParser/Go/GoLexer.cpp create mode 100644 source/Plugins/ExpressionParser/Go/GoLexer.h create mode 100644 source/Plugins/ExpressionParser/Go/GoParser.cpp create mode 100644 source/Plugins/ExpressionParser/Go/GoParser.h create mode 100644 source/Plugins/ExpressionParser/Go/GoUserExpression.cpp create mode 100644 source/Plugins/ExpressionParser/Go/GoUserExpression.h create mode 100644 source/Plugins/ExpressionParser/Go/gen_go_ast.py create mode 100644 source/Plugins/Instruction/ARM/CMakeLists.txt create mode 100644 source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp create mode 100644 source/Plugins/Instruction/ARM/EmulateInstructionARM.h create mode 100644 source/Plugins/Instruction/ARM/EmulationStateARM.cpp create mode 100644 source/Plugins/Instruction/ARM/EmulationStateARM.h create mode 100644 source/Plugins/Instruction/ARM64/CMakeLists.txt create mode 100644 source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp create mode 100644 source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h create mode 100644 source/Plugins/Instruction/CMakeLists.txt create mode 100644 source/Plugins/Instruction/MIPS/CMakeLists.txt create mode 100644 source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp create mode 100644 source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h create mode 100644 source/Plugins/Instruction/MIPS64/CMakeLists.txt create mode 100644 source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp create mode 100644 source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h create mode 100644 source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp create mode 100644 source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h create mode 100644 source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt create mode 100644 source/Plugins/InstrumentationRuntime/CMakeLists.txt create mode 100644 source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt create mode 100644 source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp create mode 100644 source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h create mode 100644 source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt create mode 100644 source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp create mode 100644 source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h create mode 100644 source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt create mode 100644 source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp create mode 100644 source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h create mode 100644 source/Plugins/JITLoader/CMakeLists.txt create mode 100644 source/Plugins/JITLoader/GDB/CMakeLists.txt create mode 100644 source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp create mode 100644 source/Plugins/JITLoader/GDB/JITLoaderGDB.h create mode 100644 source/Plugins/Language/CMakeLists.txt create mode 100644 source/Plugins/Language/CPlusPlus/BlockPointer.cpp create mode 100644 source/Plugins/Language/CPlusPlus/BlockPointer.h create mode 100644 source/Plugins/Language/CPlusPlus/CMakeLists.txt create mode 100644 source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp create mode 100644 source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h create mode 100644 source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp create mode 100644 source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h create mode 100644 source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp create mode 100644 source/Plugins/Language/CPlusPlus/CxxStringTypes.h create mode 100644 source/Plugins/Language/CPlusPlus/LibCxx.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibCxx.h create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxAtomic.h create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxList.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxMap.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibCxxVector.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibStdcpp.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibStdcpp.h create mode 100644 source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp create mode 100644 source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp create mode 100644 source/Plugins/Language/Go/CMakeLists.txt create mode 100644 source/Plugins/Language/Go/GoFormatterFunctions.cpp create mode 100644 source/Plugins/Language/Go/GoFormatterFunctions.h create mode 100644 source/Plugins/Language/Go/GoLanguage.cpp create mode 100644 source/Plugins/Language/Go/GoLanguage.h create mode 100644 source/Plugins/Language/Java/CMakeLists.txt create mode 100644 source/Plugins/Language/Java/JavaFormatterFunctions.cpp create mode 100644 source/Plugins/Language/Java/JavaFormatterFunctions.h create mode 100644 source/Plugins/Language/Java/JavaLanguage.cpp create mode 100644 source/Plugins/Language/Java/JavaLanguage.h create mode 100644 source/Plugins/Language/OCaml/CMakeLists.txt create mode 100644 source/Plugins/Language/OCaml/OCamlLanguage.cpp create mode 100644 source/Plugins/Language/OCaml/OCamlLanguage.h create mode 100644 source/Plugins/Language/ObjC/CF.cpp create mode 100644 source/Plugins/Language/ObjC/CF.h create mode 100644 source/Plugins/Language/ObjC/CMakeLists.txt create mode 100644 source/Plugins/Language/ObjC/Cocoa.cpp create mode 100644 source/Plugins/Language/ObjC/Cocoa.h create mode 100644 source/Plugins/Language/ObjC/CoreMedia.cpp create mode 100644 source/Plugins/Language/ObjC/CoreMedia.h create mode 100644 source/Plugins/Language/ObjC/NSArray.cpp create mode 100644 source/Plugins/Language/ObjC/NSDictionary.cpp create mode 100644 source/Plugins/Language/ObjC/NSDictionary.h create mode 100644 source/Plugins/Language/ObjC/NSError.cpp create mode 100644 source/Plugins/Language/ObjC/NSException.cpp create mode 100644 source/Plugins/Language/ObjC/NSIndexPath.cpp create mode 100644 source/Plugins/Language/ObjC/NSSet.cpp create mode 100644 source/Plugins/Language/ObjC/NSSet.h create mode 100644 source/Plugins/Language/ObjC/NSString.cpp create mode 100644 source/Plugins/Language/ObjC/NSString.h create mode 100644 source/Plugins/Language/ObjC/ObjCLanguage.cpp create mode 100644 source/Plugins/Language/ObjC/ObjCLanguage.h create mode 100644 source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt create mode 100644 source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp create mode 100644 source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h create mode 100644 source/Plugins/LanguageRuntime/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp create mode 100644 source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h create mode 100644 source/Plugins/LanguageRuntime/Go/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp create mode 100644 source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h create mode 100644 source/Plugins/LanguageRuntime/Java/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp create mode 100644 source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h create mode 100644 source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.cpp create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptScriptGroup.h create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp create mode 100644 source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h create mode 100644 source/Plugins/MemoryHistory/CMakeLists.txt create mode 100644 source/Plugins/MemoryHistory/asan/CMakeLists.txt create mode 100644 source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp create mode 100644 source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h create mode 100644 source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt create mode 100644 source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp create mode 100644 source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h create mode 100644 source/Plugins/ObjectContainer/CMakeLists.txt create mode 100644 source/Plugins/ObjectContainer/Universal-Mach-O/CMakeLists.txt create mode 100644 source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp create mode 100644 source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h create mode 100644 source/Plugins/ObjectFile/CMakeLists.txt create mode 100644 source/Plugins/ObjectFile/ELF/CMakeLists.txt create mode 100644 source/Plugins/ObjectFile/ELF/ELFHeader.cpp create mode 100644 source/Plugins/ObjectFile/ELF/ELFHeader.h create mode 100644 source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp create mode 100644 source/Plugins/ObjectFile/ELF/ObjectFileELF.h create mode 100644 source/Plugins/ObjectFile/JIT/CMakeLists.txt create mode 100644 source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp create mode 100644 source/Plugins/ObjectFile/JIT/ObjectFileJIT.h create mode 100644 source/Plugins/ObjectFile/Mach-O/CMakeLists.txt create mode 100644 source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp create mode 100644 source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h create mode 100644 source/Plugins/ObjectFile/PECOFF/CMakeLists.txt create mode 100644 source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp create mode 100644 source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h create mode 100644 source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.cpp create mode 100644 source/Plugins/ObjectFile/PECOFF/WindowsMiniDump.h create mode 100644 source/Plugins/OperatingSystem/CMakeLists.txt create mode 100644 source/Plugins/OperatingSystem/Go/CMakeLists.txt create mode 100644 source/Plugins/OperatingSystem/Go/OperatingSystemGo.cpp create mode 100644 source/Plugins/OperatingSystem/Go/OperatingSystemGo.h create mode 100644 source/Plugins/OperatingSystem/Python/CMakeLists.txt create mode 100644 source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp create mode 100644 source/Plugins/OperatingSystem/Python/OperatingSystemPython.h create mode 100644 source/Plugins/Platform/Android/AdbClient.cpp create mode 100644 source/Plugins/Platform/Android/AdbClient.h create mode 100644 source/Plugins/Platform/Android/CMakeLists.txt create mode 100644 source/Plugins/Platform/Android/PlatformAndroid.cpp create mode 100644 source/Plugins/Platform/Android/PlatformAndroid.h create mode 100644 source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp create mode 100644 source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h create mode 100644 source/Plugins/Platform/CMakeLists.txt create mode 100644 source/Plugins/Platform/FreeBSD/CMakeLists.txt create mode 100644 source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp create mode 100644 source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h create mode 100644 source/Plugins/Platform/Kalimba/CMakeLists.txt create mode 100644 source/Plugins/Platform/Kalimba/PlatformKalimba.cpp create mode 100644 source/Plugins/Platform/Kalimba/PlatformKalimba.h create mode 100644 source/Plugins/Platform/Linux/CMakeLists.txt create mode 100644 source/Plugins/Platform/Linux/PlatformLinux.cpp create mode 100644 source/Plugins/Platform/Linux/PlatformLinux.h create mode 100644 source/Plugins/Platform/MacOSX/CMakeLists.txt create mode 100644 source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformDarwin.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformDarwin.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformMacOSX.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp create mode 100644 source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.h create mode 100644 source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm create mode 100644 source/Plugins/Platform/NetBSD/CMakeLists.txt create mode 100644 source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp create mode 100644 source/Plugins/Platform/NetBSD/PlatformNetBSD.h create mode 100644 source/Plugins/Platform/OpenBSD/CMakeLists.txt create mode 100644 source/Plugins/Platform/OpenBSD/PlatformOpenBSD.cpp create mode 100644 source/Plugins/Platform/OpenBSD/PlatformOpenBSD.h create mode 100644 source/Plugins/Platform/POSIX/CMakeLists.txt create mode 100644 source/Plugins/Platform/POSIX/PlatformPOSIX.cpp create mode 100644 source/Plugins/Platform/POSIX/PlatformPOSIX.h create mode 100644 source/Plugins/Platform/Windows/CMakeLists.txt create mode 100644 source/Plugins/Platform/Windows/PlatformWindows.cpp create mode 100644 source/Plugins/Platform/Windows/PlatformWindows.h create mode 100644 source/Plugins/Platform/gdb-server/CMakeLists.txt create mode 100644 source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp create mode 100644 source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h create mode 100644 source/Plugins/Process/CMakeLists.txt create mode 100644 source/Plugins/Process/Darwin/CFBundle.cpp create mode 100644 source/Plugins/Process/Darwin/CFBundle.h create mode 100644 source/Plugins/Process/Darwin/CFString.cpp create mode 100644 source/Plugins/Process/Darwin/CFString.h create mode 100644 source/Plugins/Process/Darwin/CFUtils.h create mode 100644 source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp create mode 100644 source/Plugins/Process/Darwin/DarwinProcessLauncher.h create mode 100644 source/Plugins/Process/Darwin/LaunchFlavor.h create mode 100644 source/Plugins/Process/Darwin/MachException.cpp create mode 100644 source/Plugins/Process/Darwin/MachException.h create mode 100644 source/Plugins/Process/Darwin/NativeProcessDarwin.cpp create mode 100644 source/Plugins/Process/Darwin/NativeProcessDarwin.h create mode 100644 source/Plugins/Process/Darwin/NativeThreadDarwin.cpp create mode 100644 source/Plugins/Process/Darwin/NativeThreadDarwin.h create mode 100644 source/Plugins/Process/Darwin/NativeThreadListDarwin.cpp create mode 100644 source/Plugins/Process/Darwin/NativeThreadListDarwin.h create mode 100644 source/Plugins/Process/FreeBSD/CMakeLists.txt create mode 100644 source/Plugins/Process/FreeBSD/FreeBSDThread.cpp create mode 100644 source/Plugins/Process/FreeBSD/FreeBSDThread.h create mode 100644 source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp create mode 100644 source/Plugins/Process/FreeBSD/POSIXStopInfo.h create mode 100644 source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp create mode 100644 source/Plugins/Process/FreeBSD/ProcessFreeBSD.h create mode 100644 source/Plugins/Process/FreeBSD/ProcessMonitor.cpp create mode 100644 source/Plugins/Process/FreeBSD/ProcessMonitor.h create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIX.h create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp create mode 100644 source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h create mode 100644 source/Plugins/Process/Linux/CMakeLists.txt create mode 100644 source/Plugins/Process/Linux/NativeProcessLinux.cpp create mode 100644 source/Plugins/Process/Linux/NativeProcessLinux.h create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux.h create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.h create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp create mode 100644 source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h create mode 100644 source/Plugins/Process/Linux/NativeThreadLinux.cpp create mode 100644 source/Plugins/Process/Linux/NativeThreadLinux.h create mode 100644 source/Plugins/Process/Linux/ProcessorTrace.cpp create mode 100644 source/Plugins/Process/Linux/ProcessorTrace.h create mode 100644 source/Plugins/Process/Linux/Procfs.h create mode 100644 source/Plugins/Process/Linux/SingleStepCheck.cpp create mode 100644 source/Plugins/Process/Linux/SingleStepCheck.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt create mode 100644 source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h create mode 100644 source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp create mode 100644 source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h create mode 100644 source/Plugins/Process/NetBSD/CMakeLists.txt create mode 100644 source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp create mode 100644 source/Plugins/Process/NetBSD/NativeProcessNetBSD.h create mode 100644 source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp create mode 100644 source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h create mode 100644 source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp create mode 100644 source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h create mode 100644 source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp create mode 100644 source/Plugins/Process/NetBSD/NativeThreadNetBSD.h create mode 100644 source/Plugins/Process/POSIX/CMakeLists.txt create mode 100644 source/Plugins/Process/POSIX/CrashReason.cpp create mode 100644 source/Plugins/Process/POSIX/CrashReason.h create mode 100644 source/Plugins/Process/POSIX/ProcessMessage.cpp create mode 100644 source/Plugins/Process/POSIX/ProcessMessage.h create mode 100644 source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp create mode 100644 source/Plugins/Process/POSIX/ProcessPOSIXLog.h create mode 100644 source/Plugins/Process/Utility/ARMDefines.h create mode 100644 source/Plugins/Process/Utility/ARMUtils.h create mode 100644 source/Plugins/Process/Utility/CMakeLists.txt create mode 100644 source/Plugins/Process/Utility/DynamicRegisterInfo.cpp create mode 100644 source/Plugins/Process/Utility/DynamicRegisterInfo.h create mode 100644 source/Plugins/Process/Utility/FreeBSDSignals.cpp create mode 100644 source/Plugins/Process/Utility/FreeBSDSignals.h create mode 100644 source/Plugins/Process/Utility/GDBRemoteSignals.cpp create mode 100644 source/Plugins/Process/Utility/GDBRemoteSignals.h create mode 100644 source/Plugins/Process/Utility/HistoryThread.cpp create mode 100644 source/Plugins/Process/Utility/HistoryThread.h create mode 100644 source/Plugins/Process/Utility/HistoryUnwind.cpp create mode 100644 source/Plugins/Process/Utility/HistoryUnwind.h create mode 100644 source/Plugins/Process/Utility/InferiorCallPOSIX.cpp create mode 100644 source/Plugins/Process/Utility/InferiorCallPOSIX.h create mode 100644 source/Plugins/Process/Utility/InstructionUtils.h create mode 100644 source/Plugins/Process/Utility/LinuxSignals.cpp create mode 100644 source/Plugins/Process/Utility/LinuxSignals.h create mode 100644 source/Plugins/Process/Utility/MipsLinuxSignals.cpp create mode 100644 source/Plugins/Process/Utility/MipsLinuxSignals.h create mode 100644 source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp create mode 100644 source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h create mode 100644 source/Plugins/Process/Utility/NetBSDSignals.cpp create mode 100644 source/Plugins/Process/Utility/NetBSDSignals.h create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_arm.h create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_i386.h create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextDummy.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextDummy.h create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextHistory.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextHistory.h create mode 100644 source/Plugins/Process/Utility/RegisterContextLLDB.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextLLDB.h create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_i386.h create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_mips.h create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_mips64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_s390x.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_s390x.h create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h create mode 100644 source/Plugins/Process/Utility/RegisterContextMach_arm.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextMach_arm.h create mode 100644 source/Plugins/Process/Utility/RegisterContextMach_i386.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextMach_i386.h create mode 100644 source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextMach_x86_64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextMemory.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextMemory.h create mode 100644 source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextOpenBSD_i386.h create mode 100644 source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h create mode 100644 source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp create mode 100644 source/Plugins/Process/Utility/RegisterContextThreadMemory.h create mode 100644 source/Plugins/Process/Utility/RegisterContext_mips.h create mode 100644 source/Plugins/Process/Utility/RegisterContext_powerpc.h create mode 100644 source/Plugins/Process/Utility/RegisterContext_s390x.h create mode 100644 source/Plugins/Process/Utility/RegisterContext_x86.h create mode 100644 source/Plugins/Process/Utility/RegisterInfoInterface.h create mode 100644 source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp create mode 100644 source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h create mode 100644 source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp create mode 100644 source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_arm.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_arm64.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_i386.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_mips.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_mips64.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_powerpc.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_s390x.h create mode 100644 source/Plugins/Process/Utility/RegisterInfos_x86_64.h create mode 100644 source/Plugins/Process/Utility/StopInfoMachException.cpp create mode 100644 source/Plugins/Process/Utility/StopInfoMachException.h create mode 100644 source/Plugins/Process/Utility/ThreadMemory.cpp create mode 100644 source/Plugins/Process/Utility/ThreadMemory.h create mode 100644 source/Plugins/Process/Utility/UnwindLLDB.cpp create mode 100644 source/Plugins/Process/Utility/UnwindLLDB.h create mode 100644 source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp create mode 100644 source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h create mode 100644 source/Plugins/Process/Utility/lldb-arm-register-enums.h create mode 100644 source/Plugins/Process/Utility/lldb-arm64-register-enums.h create mode 100644 source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h create mode 100644 source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h create mode 100644 source/Plugins/Process/Utility/lldb-s390x-register-enums.h create mode 100644 source/Plugins/Process/Utility/lldb-x86-register-enums.h create mode 100644 source/Plugins/Process/Windows/Common/CMakeLists.txt create mode 100644 source/Plugins/Process/Windows/Common/DebuggerThread.cpp create mode 100644 source/Plugins/Process/Windows/Common/DebuggerThread.h create mode 100644 source/Plugins/Process/Windows/Common/ExceptionRecord.h create mode 100644 source/Plugins/Process/Windows/Common/ForwardDecl.h create mode 100644 source/Plugins/Process/Windows/Common/IDebugDelegate.h create mode 100644 source/Plugins/Process/Windows/Common/LocalDebugDelegate.cpp create mode 100644 source/Plugins/Process/Windows/Common/LocalDebugDelegate.h create mode 100644 source/Plugins/Process/Windows/Common/NtStructures.h create mode 100644 source/Plugins/Process/Windows/Common/ProcessWindows.cpp create mode 100644 source/Plugins/Process/Windows/Common/ProcessWindows.h create mode 100644 source/Plugins/Process/Windows/Common/ProcessWindowsLog.cpp create mode 100644 source/Plugins/Process/Windows/Common/ProcessWindowsLog.h create mode 100644 source/Plugins/Process/Windows/Common/RegisterContextWindows.cpp create mode 100644 source/Plugins/Process/Windows/Common/RegisterContextWindows.h create mode 100644 source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp create mode 100644 source/Plugins/Process/Windows/Common/TargetThreadWindows.h create mode 100644 source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp create mode 100644 source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h create mode 100644 source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp create mode 100644 source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h create mode 100644 source/Plugins/Process/elf-core/CMakeLists.txt create mode 100644 source/Plugins/Process/elf-core/ProcessElfCore.cpp create mode 100644 source/Plugins/Process/elf-core/ProcessElfCore.h create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.h create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp create mode 100644 source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h create mode 100644 source/Plugins/Process/elf-core/ThreadElfCore.cpp create mode 100644 source/Plugins/Process/elf-core/ThreadElfCore.h create mode 100644 source/Plugins/Process/gdb-remote/CMakeLists.txt create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp create mode 100644 source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h create mode 100644 source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp create mode 100644 source/Plugins/Process/gdb-remote/ProcessGDBRemote.h create mode 100644 source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp create mode 100644 source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h create mode 100644 source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp create mode 100644 source/Plugins/Process/gdb-remote/ThreadGDBRemote.h create mode 100644 source/Plugins/Process/mach-core/CMakeLists.txt create mode 100644 source/Plugins/Process/mach-core/ProcessMachCore.cpp create mode 100644 source/Plugins/Process/mach-core/ProcessMachCore.h create mode 100644 source/Plugins/Process/mach-core/ThreadMachCore.cpp create mode 100644 source/Plugins/Process/mach-core/ThreadMachCore.h create mode 100644 source/Plugins/Process/minidump/CMakeLists.txt create mode 100644 source/Plugins/Process/minidump/MinidumpParser.cpp create mode 100644 source/Plugins/Process/minidump/MinidumpParser.h create mode 100644 source/Plugins/Process/minidump/MinidumpTypes.cpp create mode 100644 source/Plugins/Process/minidump/MinidumpTypes.h create mode 100644 source/Plugins/Process/minidump/NtStructures.h create mode 100644 source/Plugins/Process/minidump/ProcessMinidump.cpp create mode 100644 source/Plugins/Process/minidump/ProcessMinidump.h create mode 100644 source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.cpp create mode 100644 source/Plugins/Process/minidump/RegisterContextMinidump_x86_32.h create mode 100644 source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp create mode 100644 source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.h create mode 100644 source/Plugins/Process/minidump/ThreadMinidump.cpp create mode 100644 source/Plugins/Process/minidump/ThreadMinidump.h create mode 100644 source/Plugins/ScriptInterpreter/CMakeLists.txt create mode 100644 source/Plugins/ScriptInterpreter/None/CMakeLists.txt create mode 100644 source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp create mode 100644 source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h create mode 100644 source/Plugins/ScriptInterpreter/Python/CMakeLists.txt create mode 100644 source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp create mode 100644 source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h create mode 100644 source/Plugins/ScriptInterpreter/Python/PythonExceptionState.cpp create mode 100644 source/Plugins/ScriptInterpreter/Python/PythonExceptionState.h create mode 100644 source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp create mode 100644 source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h create mode 100644 source/Plugins/ScriptInterpreter/Python/lldb-python.h create mode 100644 source/Plugins/StructuredData/CMakeLists.txt create mode 100644 source/Plugins/StructuredData/DarwinLog/CMakeLists.txt create mode 100644 source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp create mode 100644 source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.h create mode 100644 source/Plugins/SymbolFile/CMakeLists.txt create mode 100644 source/Plugins/SymbolFile/DWARF/CMakeLists.txt create mode 100644 source/Plugins/SymbolFile/DWARF/DIERef.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DIERef.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParser.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserGo.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserJava.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFAttribute.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDIE.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugMacro.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFDefines.h create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/DWARFFormValue.h create mode 100644 source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h create mode 100644 source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h create mode 100644 source/Plugins/SymbolFile/DWARF/NameToDIE.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/NameToDIE.h create mode 100644 source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h create mode 100644 source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h create mode 100644 source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h create mode 100644 source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp create mode 100644 source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h create mode 100644 source/Plugins/SymbolFile/PDB/CMakeLists.txt create mode 100644 source/Plugins/SymbolFile/PDB/PDBASTParser.cpp create mode 100644 source/Plugins/SymbolFile/PDB/PDBASTParser.h create mode 100644 source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp create mode 100644 source/Plugins/SymbolFile/PDB/SymbolFilePDB.h create mode 100644 source/Plugins/SymbolFile/Symtab/CMakeLists.txt create mode 100644 source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp create mode 100644 source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h create mode 100644 source/Plugins/SymbolVendor/CMakeLists.txt create mode 100644 source/Plugins/SymbolVendor/ELF/CMakeLists.txt create mode 100644 source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp create mode 100644 source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h create mode 100644 source/Plugins/SymbolVendor/MacOSX/CMakeLists.txt create mode 100644 source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp create mode 100644 source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h create mode 100644 source/Plugins/SystemRuntime/CMakeLists.txt create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp create mode 100644 source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h create mode 100644 source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt create mode 100644 source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp create mode 100644 source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h create mode 100644 source/Plugins/UnwindAssembly/CMakeLists.txt create mode 100644 source/Plugins/UnwindAssembly/InstEmulation/CMakeLists.txt create mode 100644 source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp create mode 100644 source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h create mode 100644 source/Plugins/UnwindAssembly/x86/CMakeLists.txt create mode 100644 source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp create mode 100644 source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h create mode 100644 source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp create mode 100644 source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h create mode 100644 source/Symbol/ArmUnwindInfo.cpp create mode 100644 source/Symbol/Block.cpp create mode 100644 source/Symbol/CMakeLists.txt create mode 100644 source/Symbol/ClangASTContext.cpp create mode 100644 source/Symbol/ClangASTImporter.cpp create mode 100644 source/Symbol/ClangExternalASTSourceCallbacks.cpp create mode 100644 source/Symbol/ClangExternalASTSourceCommon.cpp create mode 100644 source/Symbol/ClangUtil.cpp create mode 100644 source/Symbol/CompactUnwindInfo.cpp create mode 100644 source/Symbol/CompileUnit.cpp create mode 100644 source/Symbol/CompilerDecl.cpp create mode 100644 source/Symbol/CompilerDeclContext.cpp create mode 100644 source/Symbol/CompilerType.cpp create mode 100644 source/Symbol/DWARFCallFrameInfo.cpp create mode 100644 source/Symbol/DebugMacros.cpp create mode 100644 source/Symbol/Declaration.cpp create mode 100644 source/Symbol/FuncUnwinders.cpp create mode 100644 source/Symbol/Function.cpp create mode 100644 source/Symbol/GoASTContext.cpp create mode 100644 source/Symbol/JavaASTContext.cpp create mode 100644 source/Symbol/LineEntry.cpp create mode 100644 source/Symbol/LineTable.cpp create mode 100644 source/Symbol/OCamlASTContext.cpp create mode 100644 source/Symbol/ObjectFile.cpp create mode 100644 source/Symbol/Symbol.cpp create mode 100644 source/Symbol/SymbolContext.cpp create mode 100644 source/Symbol/SymbolFile.cpp create mode 100644 source/Symbol/SymbolVendor.cpp create mode 100644 source/Symbol/Symtab.cpp create mode 100644 source/Symbol/Type.cpp create mode 100644 source/Symbol/TypeList.cpp create mode 100644 source/Symbol/TypeMap.cpp create mode 100644 source/Symbol/TypeSystem.cpp create mode 100644 source/Symbol/UnwindPlan.cpp create mode 100644 source/Symbol/UnwindTable.cpp create mode 100644 source/Symbol/Variable.cpp create mode 100644 source/Symbol/VariableList.cpp create mode 100644 source/Symbol/VerifyDecl.cpp create mode 100644 source/Target/ABI.cpp create mode 100644 source/Target/CMakeLists.txt create mode 100644 source/Target/CPPLanguageRuntime.cpp create mode 100644 source/Target/ExecutionContext.cpp create mode 100644 source/Target/FileAction.cpp create mode 100644 source/Target/InstrumentationRuntime.cpp create mode 100644 source/Target/InstrumentationRuntimeStopInfo.cpp create mode 100644 source/Target/JITLoader.cpp create mode 100644 source/Target/JITLoaderList.cpp create mode 100644 source/Target/Language.cpp create mode 100644 source/Target/LanguageRuntime.cpp create mode 100644 source/Target/Memory.cpp create mode 100644 source/Target/MemoryHistory.cpp create mode 100644 source/Target/ModuleCache.cpp create mode 100644 source/Target/ObjCLanguageRuntime.cpp create mode 100644 source/Target/OperatingSystem.cpp create mode 100644 source/Target/PathMappingList.cpp create mode 100644 source/Target/Platform.cpp create mode 100644 source/Target/Process.cpp create mode 100644 source/Target/ProcessInfo.cpp create mode 100644 source/Target/ProcessLaunchInfo.cpp create mode 100644 source/Target/Queue.cpp create mode 100644 source/Target/QueueItem.cpp create mode 100644 source/Target/QueueList.cpp create mode 100644 source/Target/RegisterContext.cpp create mode 100644 source/Target/RegisterNumber.cpp create mode 100644 source/Target/SectionLoadHistory.cpp create mode 100644 source/Target/SectionLoadList.cpp create mode 100644 source/Target/StackFrame.cpp create mode 100644 source/Target/StackFrameList.cpp create mode 100644 source/Target/StackID.cpp create mode 100644 source/Target/StopInfo.cpp create mode 100644 source/Target/StructuredDataPlugin.cpp create mode 100644 source/Target/SystemRuntime.cpp create mode 100644 source/Target/Target.cpp create mode 100644 source/Target/TargetList.cpp create mode 100644 source/Target/Thread.cpp create mode 100644 source/Target/ThreadCollection.cpp create mode 100644 source/Target/ThreadList.cpp create mode 100644 source/Target/ThreadPlan.cpp create mode 100644 source/Target/ThreadPlanBase.cpp create mode 100644 source/Target/ThreadPlanCallFunction.cpp create mode 100644 source/Target/ThreadPlanCallFunctionUsingABI.cpp create mode 100644 source/Target/ThreadPlanCallOnFunctionExit.cpp create mode 100644 source/Target/ThreadPlanCallUserExpression.cpp create mode 100644 source/Target/ThreadPlanPython.cpp create mode 100644 source/Target/ThreadPlanRunToAddress.cpp create mode 100644 source/Target/ThreadPlanShouldStopHere.cpp create mode 100644 source/Target/ThreadPlanStepInRange.cpp create mode 100644 source/Target/ThreadPlanStepInstruction.cpp create mode 100644 source/Target/ThreadPlanStepOut.cpp create mode 100644 source/Target/ThreadPlanStepOverBreakpoint.cpp create mode 100644 source/Target/ThreadPlanStepOverRange.cpp create mode 100644 source/Target/ThreadPlanStepRange.cpp create mode 100644 source/Target/ThreadPlanStepThrough.cpp create mode 100644 source/Target/ThreadPlanStepUntil.cpp create mode 100644 source/Target/ThreadPlanTracer.cpp create mode 100644 source/Target/ThreadSpec.cpp create mode 100644 source/Target/UnixSignals.cpp create mode 100644 source/Target/UnwindAssembly.cpp create mode 100644 source/Utility/ARM64_DWARF_Registers.h create mode 100644 source/Utility/ARM64_ehframe_Registers.h create mode 100644 source/Utility/ARM_DWARF_Registers.h create mode 100644 source/Utility/ARM_ehframe_Registers.h create mode 100644 source/Utility/Baton.cpp create mode 100644 source/Utility/CMakeLists.txt create mode 100644 source/Utility/Connection.cpp create mode 100644 source/Utility/ConstString.cpp create mode 100644 source/Utility/DataBufferHeap.cpp create mode 100644 source/Utility/DataBufferLLVM.cpp create mode 100644 source/Utility/DataEncoder.cpp create mode 100644 source/Utility/DataExtractor.cpp create mode 100644 source/Utility/FastDemangle.cpp create mode 100644 source/Utility/FileSpec.cpp create mode 100644 source/Utility/History.cpp create mode 100644 source/Utility/IOObject.cpp create mode 100644 source/Utility/JSON.cpp create mode 100644 source/Utility/LLDBAssert.cpp create mode 100644 source/Utility/Log.cpp create mode 100644 source/Utility/Logging.cpp create mode 100644 source/Utility/NameMatches.cpp create mode 100644 source/Utility/Range.cpp create mode 100644 source/Utility/RegularExpression.cpp create mode 100644 source/Utility/SelectHelper.cpp create mode 100644 source/Utility/SharingPtr.cpp create mode 100644 source/Utility/Status.cpp create mode 100644 source/Utility/Stream.cpp create mode 100644 source/Utility/StreamCallback.cpp create mode 100644 source/Utility/StreamGDBRemote.cpp create mode 100644 source/Utility/StreamString.cpp create mode 100644 source/Utility/StringExtractor.cpp create mode 100644 source/Utility/StringExtractorGDBRemote.cpp create mode 100644 source/Utility/StringExtractorGDBRemote.h create mode 100644 source/Utility/StringLexer.cpp create mode 100644 source/Utility/StringList.cpp create mode 100644 source/Utility/StructuredData.cpp create mode 100644 source/Utility/TaskPool.cpp create mode 100644 source/Utility/TildeExpressionResolver.cpp create mode 100644 source/Utility/Timer.cpp create mode 100644 source/Utility/UUID.cpp create mode 100644 source/Utility/UriParser.cpp create mode 100644 source/Utility/UserID.cpp create mode 100644 source/Utility/UuidCompatibility.h create mode 100644 source/Utility/VASprintf.cpp create mode 100644 source/Utility/VMRange.cpp create mode 100644 source/lldb.cpp create mode 100644 test/CMakeLists.txt create mode 100755 test/dotest.py create mode 100644 test/use_lldb_suite.py create mode 100644 third_party/Python/module/pexpect-2.4/ANSI.py create mode 100644 third_party/Python/module/pexpect-2.4/FSM.py create mode 100644 third_party/Python/module/pexpect-2.4/INSTALL create mode 100644 third_party/Python/module/pexpect-2.4/LICENSE create mode 100644 third_party/Python/module/pexpect-2.4/PKG-INFO create mode 100644 third_party/Python/module/pexpect-2.4/README create mode 100644 third_party/Python/module/pexpect-2.4/doc/clean.css create mode 100644 third_party/Python/module/pexpect-2.4/doc/email.png create mode 100644 third_party/Python/module/pexpect-2.4/doc/examples.html create mode 100644 third_party/Python/module/pexpect-2.4/doc/index.html create mode 100644 third_party/Python/module/pexpect-2.4/doc/index.template.html create mode 100644 third_party/Python/module/pexpect-2.4/examples/README create mode 100644 third_party/Python/module/pexpect-2.4/examples/astat.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/bd_client.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/bd_serv.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/cgishell.cgi create mode 100644 third_party/Python/module/pexpect-2.4/examples/chess.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/chess2.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/chess3.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/df.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/fix_cvs_files.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/ftp.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/hive.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/monitor.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/passmass.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/python.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/rippy.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/script.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/ssh_session.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/ssh_tunnel.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/sshls.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/table_test.html create mode 100644 third_party/Python/module/pexpect-2.4/examples/topip.py create mode 100644 third_party/Python/module/pexpect-2.4/examples/uptime.py create mode 100644 third_party/Python/module/pexpect-2.4/fdpexpect.py create mode 100644 third_party/Python/module/pexpect-2.4/pexpect.py create mode 100644 third_party/Python/module/pexpect-2.4/pxssh.py create mode 100644 third_party/Python/module/pexpect-2.4/screen.py create mode 100644 third_party/Python/module/pexpect-2.4/setup.py create mode 100644 third_party/Python/module/progress/progress.py create mode 100644 third_party/Python/module/six/LICENSE create mode 100644 third_party/Python/module/six/six.py create mode 100644 third_party/Python/module/unittest2/unittest2/__init__.py create mode 100644 third_party/Python/module/unittest2/unittest2/__main__.py create mode 100644 third_party/Python/module/unittest2/unittest2/case.py create mode 100644 third_party/Python/module/unittest2/unittest2/collector.py create mode 100644 third_party/Python/module/unittest2/unittest2/compatibility.py create mode 100644 third_party/Python/module/unittest2/unittest2/loader.py create mode 100644 third_party/Python/module/unittest2/unittest2/main.py create mode 100644 third_party/Python/module/unittest2/unittest2/result.py create mode 100644 third_party/Python/module/unittest2/unittest2/runner.py create mode 100644 third_party/Python/module/unittest2/unittest2/signals.py create mode 100644 third_party/Python/module/unittest2/unittest2/suite.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/__init__.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/dummy.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/support.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_assertions.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_break.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_case.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_discovery.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_functiontestcase.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_loader.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_new_tests.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_program.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_result.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_runner.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_setups.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_skipping.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_suite.py create mode 100644 third_party/Python/module/unittest2/unittest2/test/test_unittest2_with.py create mode 100644 third_party/Python/module/unittest2/unittest2/util.py create mode 100644 tools/CMakeLists.txt create mode 100644 tools/argdumper/CMakeLists.txt create mode 100644 tools/argdumper/argdumper.cpp create mode 100644 tools/argdumper/argdumper.exports create mode 100644 tools/compact-unwind/compact-unwind-dumper.c create mode 100644 tools/darwin-debug/CMakeLists.txt create mode 100644 tools/darwin-debug/darwin-debug.cpp create mode 100644 tools/darwin-threads/examine-threads.c create mode 100644 tools/debugserver/CMakeLists.txt create mode 100644 tools/debugserver/debugnub-exports create mode 100644 tools/debugserver/debugserver.xcodeproj/project.pbxproj create mode 100644 tools/debugserver/debugserver.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 tools/debugserver/debugserver.xcodeproj/xcshareddata/xcschemes/debugserver.xcscheme create mode 100644 tools/debugserver/resources/lldb-debugserver-Info.plist create mode 100644 tools/debugserver/scripts/diagnose-termination.d create mode 100644 tools/debugserver/source/ARM_DWARF_Registers.h create mode 100644 tools/debugserver/source/ARM_ehframe_Registers.h create mode 100644 tools/debugserver/source/CMakeLists.txt create mode 100644 tools/debugserver/source/ChangeLog create mode 100644 tools/debugserver/source/DNB.cpp create mode 100644 tools/debugserver/source/DNB.h create mode 100644 tools/debugserver/source/DNBArch.cpp create mode 100644 tools/debugserver/source/DNBArch.h create mode 100644 tools/debugserver/source/DNBBreakpoint.cpp create mode 100644 tools/debugserver/source/DNBBreakpoint.h create mode 100644 tools/debugserver/source/DNBDataRef.cpp create mode 100644 tools/debugserver/source/DNBDataRef.h create mode 100644 tools/debugserver/source/DNBDefs.h create mode 100644 tools/debugserver/source/DNBError.cpp create mode 100644 tools/debugserver/source/DNBError.h create mode 100644 tools/debugserver/source/DNBLog.cpp create mode 100644 tools/debugserver/source/DNBLog.h create mode 100644 tools/debugserver/source/DNBRegisterInfo.cpp create mode 100644 tools/debugserver/source/DNBRegisterInfo.h create mode 100644 tools/debugserver/source/DNBRuntimeAction.h create mode 100644 tools/debugserver/source/DNBThreadResumeActions.cpp create mode 100644 tools/debugserver/source/DNBThreadResumeActions.h create mode 100644 tools/debugserver/source/DNBTimer.h create mode 100644 tools/debugserver/source/JSON.cpp create mode 100644 tools/debugserver/source/JSON.h create mode 100644 tools/debugserver/source/JSONGenerator.h create mode 100644 tools/debugserver/source/MacOSX/CFBundle.cpp create mode 100644 tools/debugserver/source/MacOSX/CFBundle.h create mode 100644 tools/debugserver/source/MacOSX/CFString.cpp create mode 100644 tools/debugserver/source/MacOSX/CFString.h create mode 100644 tools/debugserver/source/MacOSX/CFUtils.h create mode 100644 tools/debugserver/source/MacOSX/CMakeLists.txt create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/CMakeLists.txt create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/DarwinLogEvent.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/DarwinLogInterfaces.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/DarwinLogTypes.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilter.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilter.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogMessage.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogMessage.h create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.cpp create mode 100644 tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.h create mode 100644 tools/debugserver/source/MacOSX/Genealogy.cpp create mode 100644 tools/debugserver/source/MacOSX/Genealogy.h create mode 100644 tools/debugserver/source/MacOSX/GenealogySPI.h create mode 100644 tools/debugserver/source/MacOSX/MachException.cpp create mode 100644 tools/debugserver/source/MacOSX/MachException.h create mode 100644 tools/debugserver/source/MacOSX/MachProcess.h create mode 100644 tools/debugserver/source/MacOSX/MachProcess.mm create mode 100644 tools/debugserver/source/MacOSX/MachTask.h create mode 100644 tools/debugserver/source/MacOSX/MachTask.mm create mode 100644 tools/debugserver/source/MacOSX/MachThread.cpp create mode 100644 tools/debugserver/source/MacOSX/MachThread.h create mode 100644 tools/debugserver/source/MacOSX/MachThreadList.cpp create mode 100644 tools/debugserver/source/MacOSX/MachThreadList.h create mode 100644 tools/debugserver/source/MacOSX/MachVMMemory.cpp create mode 100644 tools/debugserver/source/MacOSX/MachVMMemory.h create mode 100644 tools/debugserver/source/MacOSX/MachVMRegion.cpp create mode 100644 tools/debugserver/source/MacOSX/MachVMRegion.h create mode 100644 tools/debugserver/source/MacOSX/OsLogger.cpp create mode 100644 tools/debugserver/source/MacOSX/OsLogger.h create mode 100644 tools/debugserver/source/MacOSX/ThreadInfo.h create mode 100644 tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp create mode 100644 tools/debugserver/source/MacOSX/arm/DNBArchImpl.h create mode 100644 tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp create mode 100644 tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h create mode 100644 tools/debugserver/source/MacOSX/dbgnub-mig.defs create mode 100644 tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp create mode 100644 tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h create mode 100644 tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h create mode 100644 tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp create mode 100644 tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h create mode 100644 tools/debugserver/source/MacOSX/stack_logging.h create mode 100644 tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp create mode 100644 tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h create mode 100644 tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h create mode 100644 tools/debugserver/source/PThreadCondition.h create mode 100644 tools/debugserver/source/PThreadEvent.cpp create mode 100644 tools/debugserver/source/PThreadEvent.h create mode 100644 tools/debugserver/source/PThreadMutex.cpp create mode 100644 tools/debugserver/source/PThreadMutex.h create mode 100644 tools/debugserver/source/PseudoTerminal.cpp create mode 100644 tools/debugserver/source/PseudoTerminal.h create mode 100644 tools/debugserver/source/RNBContext.cpp create mode 100644 tools/debugserver/source/RNBContext.h create mode 100644 tools/debugserver/source/RNBDefs.h create mode 100644 tools/debugserver/source/RNBRemote.cpp create mode 100644 tools/debugserver/source/RNBRemote.h create mode 100644 tools/debugserver/source/RNBServices.cpp create mode 100644 tools/debugserver/source/RNBServices.h create mode 100644 tools/debugserver/source/RNBSocket.cpp create mode 100644 tools/debugserver/source/RNBSocket.h create mode 100644 tools/debugserver/source/StdStringExtractor.cpp create mode 100644 tools/debugserver/source/StdStringExtractor.h create mode 100644 tools/debugserver/source/SysSignal.cpp create mode 100644 tools/debugserver/source/SysSignal.h create mode 100644 tools/debugserver/source/TTYState.cpp create mode 100644 tools/debugserver/source/TTYState.h create mode 100644 tools/debugserver/source/com.apple.debugserver.applist.internal.plist create mode 100644 tools/debugserver/source/com.apple.debugserver.applist.plist create mode 100644 tools/debugserver/source/com.apple.debugserver.internal.plist create mode 100644 tools/debugserver/source/com.apple.debugserver.plist create mode 100644 tools/debugserver/source/com.apple.debugserver.posix.plist create mode 100644 tools/debugserver/source/debugserver-entitlements.plist create mode 100644 tools/debugserver/source/debugserver-macosx-entitlements.plist create mode 100644 tools/debugserver/source/debugserver.cpp create mode 100644 tools/debugserver/source/libdebugserver.cpp create mode 100644 tools/debugserver/source/libdebugserver.h create mode 100644 tools/driver/CMakeLists.txt create mode 100644 tools/driver/Driver.cpp create mode 100644 tools/driver/Driver.h create mode 100644 tools/driver/Platform.cpp create mode 100644 tools/driver/Platform.h create mode 100644 tools/driver/lldb-Info.plist create mode 100644 tools/install-headers/Makefile create mode 100644 tools/intel-mpx/CMakeLists.txt create mode 100644 tools/intel-mpx/IntelMPXTablePlugin.cpp create mode 100644 tools/intel-mpx/test/Makefile create mode 100644 tools/intel-mpx/test/README.txt create mode 100644 tools/intel-mpx/test/TestMPXTable.py create mode 100644 tools/intel-mpx/test/main.cpp create mode 100644 tools/lldb-mi/CMakeLists.txt create mode 100644 tools/lldb-mi/MICmdArgContext.cpp create mode 100644 tools/lldb-mi/MICmdArgContext.h create mode 100644 tools/lldb-mi/MICmdArgSet.cpp create mode 100644 tools/lldb-mi/MICmdArgSet.h create mode 100644 tools/lldb-mi/MICmdArgValBase.cpp create mode 100644 tools/lldb-mi/MICmdArgValBase.h create mode 100644 tools/lldb-mi/MICmdArgValConsume.cpp create mode 100644 tools/lldb-mi/MICmdArgValConsume.h create mode 100644 tools/lldb-mi/MICmdArgValFile.cpp create mode 100644 tools/lldb-mi/MICmdArgValFile.h create mode 100644 tools/lldb-mi/MICmdArgValListBase.cpp create mode 100644 tools/lldb-mi/MICmdArgValListBase.h create mode 100644 tools/lldb-mi/MICmdArgValListOfN.cpp create mode 100644 tools/lldb-mi/MICmdArgValListOfN.h create mode 100644 tools/lldb-mi/MICmdArgValNumber.cpp create mode 100644 tools/lldb-mi/MICmdArgValNumber.h create mode 100644 tools/lldb-mi/MICmdArgValOptionLong.cpp create mode 100644 tools/lldb-mi/MICmdArgValOptionLong.h create mode 100644 tools/lldb-mi/MICmdArgValOptionShort.cpp create mode 100644 tools/lldb-mi/MICmdArgValOptionShort.h create mode 100644 tools/lldb-mi/MICmdArgValPrintValues.cpp create mode 100644 tools/lldb-mi/MICmdArgValPrintValues.h create mode 100644 tools/lldb-mi/MICmdArgValString.cpp create mode 100644 tools/lldb-mi/MICmdArgValString.h create mode 100644 tools/lldb-mi/MICmdArgValThreadGrp.cpp create mode 100644 tools/lldb-mi/MICmdArgValThreadGrp.h create mode 100644 tools/lldb-mi/MICmdBase.cpp create mode 100644 tools/lldb-mi/MICmdBase.h create mode 100644 tools/lldb-mi/MICmdCmd.cpp create mode 100644 tools/lldb-mi/MICmdCmd.h create mode 100644 tools/lldb-mi/MICmdCmdBreak.cpp create mode 100644 tools/lldb-mi/MICmdCmdBreak.h create mode 100644 tools/lldb-mi/MICmdCmdData.cpp create mode 100644 tools/lldb-mi/MICmdCmdData.h create mode 100644 tools/lldb-mi/MICmdCmdEnviro.cpp create mode 100644 tools/lldb-mi/MICmdCmdEnviro.h create mode 100644 tools/lldb-mi/MICmdCmdExec.cpp create mode 100644 tools/lldb-mi/MICmdCmdExec.h create mode 100644 tools/lldb-mi/MICmdCmdFile.cpp create mode 100644 tools/lldb-mi/MICmdCmdFile.h create mode 100644 tools/lldb-mi/MICmdCmdGdbInfo.cpp create mode 100644 tools/lldb-mi/MICmdCmdGdbInfo.h create mode 100644 tools/lldb-mi/MICmdCmdGdbSet.cpp create mode 100644 tools/lldb-mi/MICmdCmdGdbSet.h create mode 100644 tools/lldb-mi/MICmdCmdGdbShow.cpp create mode 100644 tools/lldb-mi/MICmdCmdGdbShow.h create mode 100644 tools/lldb-mi/MICmdCmdGdbThread.cpp create mode 100644 tools/lldb-mi/MICmdCmdGdbThread.h create mode 100644 tools/lldb-mi/MICmdCmdMiscellanous.cpp create mode 100644 tools/lldb-mi/MICmdCmdMiscellanous.h create mode 100644 tools/lldb-mi/MICmdCmdStack.cpp create mode 100644 tools/lldb-mi/MICmdCmdStack.h create mode 100644 tools/lldb-mi/MICmdCmdSupportInfo.cpp create mode 100644 tools/lldb-mi/MICmdCmdSupportInfo.h create mode 100644 tools/lldb-mi/MICmdCmdSupportList.cpp create mode 100644 tools/lldb-mi/MICmdCmdSupportList.h create mode 100644 tools/lldb-mi/MICmdCmdSymbol.cpp create mode 100644 tools/lldb-mi/MICmdCmdSymbol.h create mode 100644 tools/lldb-mi/MICmdCmdTarget.cpp create mode 100644 tools/lldb-mi/MICmdCmdTarget.h create mode 100644 tools/lldb-mi/MICmdCmdThread.cpp create mode 100644 tools/lldb-mi/MICmdCmdThread.h create mode 100644 tools/lldb-mi/MICmdCmdTrace.cpp create mode 100644 tools/lldb-mi/MICmdCmdTrace.h create mode 100644 tools/lldb-mi/MICmdCmdVar.cpp create mode 100644 tools/lldb-mi/MICmdCmdVar.h create mode 100644 tools/lldb-mi/MICmdCommands.cpp create mode 100644 tools/lldb-mi/MICmdCommands.h create mode 100644 tools/lldb-mi/MICmdData.cpp create mode 100644 tools/lldb-mi/MICmdData.h create mode 100644 tools/lldb-mi/MICmdFactory.cpp create mode 100644 tools/lldb-mi/MICmdFactory.h create mode 100644 tools/lldb-mi/MICmdInterpreter.cpp create mode 100644 tools/lldb-mi/MICmdInterpreter.h create mode 100644 tools/lldb-mi/MICmdInvoker.cpp create mode 100644 tools/lldb-mi/MICmdInvoker.h create mode 100644 tools/lldb-mi/MICmdMgr.cpp create mode 100644 tools/lldb-mi/MICmdMgr.h create mode 100644 tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.cpp create mode 100644 tools/lldb-mi/MICmdMgrSetCmdDeleteCallback.h create mode 100644 tools/lldb-mi/MICmnBase.cpp create mode 100644 tools/lldb-mi/MICmnBase.h create mode 100644 tools/lldb-mi/MICmnConfig.h create mode 100644 tools/lldb-mi/MICmnLLDBBroadcaster.cpp create mode 100644 tools/lldb-mi/MICmnLLDBBroadcaster.h create mode 100644 tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp create mode 100644 tools/lldb-mi/MICmnLLDBDebugSessionInfo.h create mode 100644 tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.cpp create mode 100644 tools/lldb-mi/MICmnLLDBDebugSessionInfoVarObj.h create mode 100644 tools/lldb-mi/MICmnLLDBDebugger.cpp create mode 100644 tools/lldb-mi/MICmnLLDBDebugger.h create mode 100644 tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp create mode 100644 tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h create mode 100644 tools/lldb-mi/MICmnLLDBProxySBValue.cpp create mode 100644 tools/lldb-mi/MICmnLLDBProxySBValue.h create mode 100644 tools/lldb-mi/MICmnLLDBUtilSBValue.cpp create mode 100644 tools/lldb-mi/MICmnLLDBUtilSBValue.h create mode 100644 tools/lldb-mi/MICmnLog.cpp create mode 100644 tools/lldb-mi/MICmnLog.h create mode 100644 tools/lldb-mi/MICmnLogMediumFile.cpp create mode 100644 tools/lldb-mi/MICmnLogMediumFile.h create mode 100644 tools/lldb-mi/MICmnMIOutOfBandRecord.cpp create mode 100644 tools/lldb-mi/MICmnMIOutOfBandRecord.h create mode 100644 tools/lldb-mi/MICmnMIResultRecord.cpp create mode 100644 tools/lldb-mi/MICmnMIResultRecord.h create mode 100644 tools/lldb-mi/MICmnMIValue.cpp create mode 100644 tools/lldb-mi/MICmnMIValue.h create mode 100644 tools/lldb-mi/MICmnMIValueConst.cpp create mode 100644 tools/lldb-mi/MICmnMIValueConst.h create mode 100644 tools/lldb-mi/MICmnMIValueList.cpp create mode 100644 tools/lldb-mi/MICmnMIValueList.h create mode 100644 tools/lldb-mi/MICmnMIValueResult.cpp create mode 100644 tools/lldb-mi/MICmnMIValueResult.h create mode 100644 tools/lldb-mi/MICmnMIValueTuple.cpp create mode 100644 tools/lldb-mi/MICmnMIValueTuple.h create mode 100644 tools/lldb-mi/MICmnResources.cpp create mode 100644 tools/lldb-mi/MICmnResources.h create mode 100644 tools/lldb-mi/MICmnStreamStderr.cpp create mode 100644 tools/lldb-mi/MICmnStreamStderr.h create mode 100644 tools/lldb-mi/MICmnStreamStdin.cpp create mode 100644 tools/lldb-mi/MICmnStreamStdin.h create mode 100644 tools/lldb-mi/MICmnStreamStdout.cpp create mode 100644 tools/lldb-mi/MICmnStreamStdout.h create mode 100644 tools/lldb-mi/MICmnThreadMgrStd.cpp create mode 100644 tools/lldb-mi/MICmnThreadMgrStd.h create mode 100644 tools/lldb-mi/MIDataTypes.h create mode 100644 tools/lldb-mi/MIDriver.cpp create mode 100644 tools/lldb-mi/MIDriver.h create mode 100644 tools/lldb-mi/MIDriverBase.cpp create mode 100644 tools/lldb-mi/MIDriverBase.h create mode 100644 tools/lldb-mi/MIDriverMain.cpp create mode 100644 tools/lldb-mi/MIDriverMgr.cpp create mode 100644 tools/lldb-mi/MIDriverMgr.h create mode 100644 tools/lldb-mi/MIExtensions.txt create mode 100644 tools/lldb-mi/MIReadMe.txt create mode 100644 tools/lldb-mi/MIUtilDateTimeStd.cpp create mode 100644 tools/lldb-mi/MIUtilDateTimeStd.h create mode 100644 tools/lldb-mi/MIUtilDebug.cpp create mode 100644 tools/lldb-mi/MIUtilDebug.h create mode 100644 tools/lldb-mi/MIUtilFileStd.cpp create mode 100644 tools/lldb-mi/MIUtilFileStd.h create mode 100644 tools/lldb-mi/MIUtilMapIdToVariant.cpp create mode 100644 tools/lldb-mi/MIUtilMapIdToVariant.h create mode 100644 tools/lldb-mi/MIUtilSingletonBase.h create mode 100644 tools/lldb-mi/MIUtilSingletonHelper.h create mode 100644 tools/lldb-mi/MIUtilString.cpp create mode 100644 tools/lldb-mi/MIUtilString.h create mode 100644 tools/lldb-mi/MIUtilThreadBaseStd.cpp create mode 100644 tools/lldb-mi/MIUtilThreadBaseStd.h create mode 100644 tools/lldb-mi/MIUtilVariant.cpp create mode 100644 tools/lldb-mi/MIUtilVariant.h create mode 100644 tools/lldb-mi/Platform.h create mode 100644 tools/lldb-mi/lldb-Info.plist create mode 100644 tools/lldb-mi/lldb-mi.exports create mode 100644 tools/lldb-perf/README create mode 100755 tools/lldb-perf/common/clang/build-clang.sh create mode 100644 tools/lldb-perf/common/clang/lldb_perf_clang.cpp create mode 100644 tools/lldb-perf/common/clang/main.cpp create mode 100644 tools/lldb-perf/common/stepping/lldb-perf-stepping.cpp create mode 100644 tools/lldb-perf/common/stepping/stepping-testcase.cpp create mode 100644 tools/lldb-perf/darwin/formatters/fmts_tester.mm create mode 100644 tools/lldb-perf/darwin/formatters/formatters.cpp create mode 100644 tools/lldb-perf/darwin/sketch/foobar.sketch2 create mode 100644 tools/lldb-perf/darwin/sketch/sketch.cpp create mode 100644 tools/lldb-perf/lib/Gauge.cpp create mode 100644 tools/lldb-perf/lib/Gauge.h create mode 100644 tools/lldb-perf/lib/Measurement.h create mode 100644 tools/lldb-perf/lib/MemoryGauge.cpp create mode 100644 tools/lldb-perf/lib/MemoryGauge.h create mode 100644 tools/lldb-perf/lib/Metric.cpp create mode 100644 tools/lldb-perf/lib/Metric.h create mode 100644 tools/lldb-perf/lib/Results.cpp create mode 100644 tools/lldb-perf/lib/Results.h create mode 100644 tools/lldb-perf/lib/TestCase.cpp create mode 100644 tools/lldb-perf/lib/TestCase.h create mode 100644 tools/lldb-perf/lib/Timer.cpp create mode 100644 tools/lldb-perf/lib/Timer.h create mode 100644 tools/lldb-perf/lib/Xcode.cpp create mode 100644 tools/lldb-perf/lib/Xcode.h create mode 100644 tools/lldb-perf/lldbperf.xcodeproj/project.pbxproj create mode 100644 tools/lldb-server/Acceptor.cpp create mode 100644 tools/lldb-server/Acceptor.h create mode 100644 tools/lldb-server/CMakeLists.txt create mode 100644 tools/lldb-server/Darwin/resources/lldb-server-Info.plist create mode 100644 tools/lldb-server/Darwin/resources/lldb-server-entitlements.plist create mode 100644 tools/lldb-server/Darwin/resources/lldb-server-macos-entitlements.plist create mode 100644 tools/lldb-server/Darwin/resources/lldb-server-mig.defs create mode 100644 tools/lldb-server/LLDBServerUtilities.cpp create mode 100644 tools/lldb-server/LLDBServerUtilities.h create mode 100644 tools/lldb-server/lldb-gdbserver.cpp create mode 100644 tools/lldb-server/lldb-platform.cpp create mode 100644 tools/lldb-server/lldb-server.cpp create mode 100644 tools/lldb-server/lldb-server.exports create mode 100644 unittests/Breakpoint/BreakpointIDTest.cpp create mode 100644 unittests/Breakpoint/CMakeLists.txt create mode 100644 unittests/CMakeLists.txt create mode 100644 unittests/Core/ArchSpecTest.cpp create mode 100644 unittests/Core/BroadcasterTest.cpp create mode 100644 unittests/Core/CMakeLists.txt create mode 100644 unittests/Core/DataExtractorTest.cpp create mode 100644 unittests/Core/ListenerTest.cpp create mode 100644 unittests/Core/ScalarTest.cpp create mode 100644 unittests/Core/StateTest.cpp create mode 100644 unittests/Core/StreamCallbackTest.cpp create mode 100644 unittests/Editline/CMakeLists.txt create mode 100644 unittests/Editline/EditlineTest.cpp create mode 100644 unittests/Expression/CMakeLists.txt create mode 100644 unittests/Expression/GoParserTest.cpp create mode 100644 unittests/Host/CMakeLists.txt create mode 100644 unittests/Host/FileSpecTest.cpp create mode 100644 unittests/Host/FileSystemTest.cpp create mode 100644 unittests/Host/HostTest.cpp create mode 100644 unittests/Host/MainLoopTest.cpp create mode 100644 unittests/Host/SocketAddressTest.cpp create mode 100644 unittests/Host/SocketTest.cpp create mode 100644 unittests/Host/SymbolsTest.cpp create mode 100644 unittests/Host/linux/HostTest.cpp create mode 100644 unittests/Host/linux/SupportTest.cpp create mode 100644 unittests/Interpreter/CMakeLists.txt create mode 100644 unittests/Interpreter/TestArgs.cpp create mode 100644 unittests/Interpreter/TestCompletion.cpp create mode 100644 unittests/Language/CMakeLists.txt create mode 100644 unittests/Language/CPlusPlus/CMakeLists.txt create mode 100644 unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp create mode 100644 unittests/ObjectFile/CMakeLists.txt create mode 100644 unittests/ObjectFile/ELF/CMakeLists.txt create mode 100644 unittests/ObjectFile/ELF/Inputs/sections-resolve-consistently.yaml create mode 100644 unittests/ObjectFile/ELF/TestELFHeader.cpp create mode 100644 unittests/ObjectFile/ELF/TestObjectFileELF.cpp create mode 100644 unittests/Platform/CMakeLists.txt create mode 100644 unittests/Platform/PlatformDarwinTest.cpp create mode 100644 unittests/Process/CMakeLists.txt create mode 100644 unittests/Process/Linux/CMakeLists.txt create mode 100644 unittests/Process/Linux/ProcessorTraceTest.cpp create mode 100644 unittests/Process/gdb-remote/CMakeLists.txt create mode 100644 unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp create mode 100644 unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp create mode 100644 unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp create mode 100644 unittests/Process/gdb-remote/GDBRemoteTestUtils.h create mode 100644 unittests/Process/minidump/CMakeLists.txt create mode 100644 unittests/Process/minidump/Inputs/fizzbuzz_no_heap.dmp create mode 100644 unittests/Process/minidump/Inputs/fizzbuzz_wow64.dmp create mode 100644 unittests/Process/minidump/Inputs/linux-i386.dmp create mode 100644 unittests/Process/minidump/Inputs/linux-x86_64.cpp create mode 100644 unittests/Process/minidump/Inputs/linux-x86_64.dmp create mode 100644 unittests/Process/minidump/Inputs/linux-x86_64_not_crashed.dmp create mode 100644 unittests/Process/minidump/MinidumpParserTest.cpp create mode 100644 unittests/ScriptInterpreter/CMakeLists.txt create mode 100644 unittests/ScriptInterpreter/Python/CMakeLists.txt create mode 100644 unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp create mode 100644 unittests/ScriptInterpreter/Python/PythonExceptionStateTests.cpp create mode 100644 unittests/ScriptInterpreter/Python/PythonTestSuite.cpp create mode 100644 unittests/ScriptInterpreter/Python/PythonTestSuite.h create mode 100644 unittests/Signals/CMakeLists.txt create mode 100644 unittests/Signals/UnixSignalsTest.cpp create mode 100644 unittests/Symbol/CMakeLists.txt create mode 100644 unittests/Symbol/Inputs/basic-call-frame-info.yaml create mode 100644 unittests/Symbol/TestClangASTContext.cpp create mode 100644 unittests/Symbol/TestDWARFCallFrameInfo.cpp create mode 100644 unittests/Symbol/TestType.cpp create mode 100644 unittests/SymbolFile/CMakeLists.txt create mode 100644 unittests/SymbolFile/DWARF/CMakeLists.txt create mode 100644 unittests/SymbolFile/DWARF/Inputs/test-dwarf.cpp create mode 100644 unittests/SymbolFile/DWARF/Inputs/test-dwarf.exe create mode 100644 unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp create mode 100644 unittests/SymbolFile/PDB/CMakeLists.txt create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb-alt.cpp create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb-nested.h create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb-types.cpp create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb-types.exe create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb-types.pdb create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb.cpp create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb.exe create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb.h create mode 100644 unittests/SymbolFile/PDB/Inputs/test-pdb.pdb create mode 100644 unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp create mode 100644 unittests/Target/CMakeLists.txt create mode 100644 unittests/Target/Inputs/TestModule.c create mode 100644 unittests/Target/Inputs/TestModule.so create mode 100644 unittests/Target/MemoryRegionInfoTest.cpp create mode 100644 unittests/Target/ModuleCacheTest.cpp create mode 100644 unittests/UnwindAssembly/CMakeLists.txt create mode 100644 unittests/UnwindAssembly/InstEmulation/CMakeLists.txt create mode 100644 unittests/UnwindAssembly/InstEmulation/TestArm64InstEmulation.cpp create mode 100644 unittests/UnwindAssembly/x86/CMakeLists.txt create mode 100644 unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp create mode 100644 unittests/Utility/CMakeLists.txt create mode 100644 unittests/Utility/ConstStringTest.cpp create mode 100644 unittests/Utility/Helpers/CMakeLists.txt create mode 100644 unittests/Utility/Helpers/MockTildeExpressionResolver.cpp create mode 100644 unittests/Utility/Helpers/MockTildeExpressionResolver.h create mode 100644 unittests/Utility/Helpers/TestUtilities.cpp create mode 100644 unittests/Utility/Helpers/TestUtilities.h create mode 100644 unittests/Utility/Inputs/StructuredData-basic.json create mode 100644 unittests/Utility/LogTest.cpp create mode 100644 unittests/Utility/NameMatchesTest.cpp create mode 100644 unittests/Utility/StatusTest.cpp create mode 100644 unittests/Utility/StringExtractorTest.cpp create mode 100644 unittests/Utility/StructuredDataTest.cpp create mode 100644 unittests/Utility/TaskPoolTest.cpp create mode 100644 unittests/Utility/TildeExpressionResolverTest.cpp create mode 100644 unittests/Utility/TimeoutTest.cpp create mode 100644 unittests/Utility/TimerTest.cpp create mode 100644 unittests/Utility/UriParserTest.cpp create mode 100644 unittests/Utility/VASprintfTest.cpp create mode 100644 unittests/debugserver/CMakeLists.txt create mode 100644 unittests/debugserver/RNBSocketTest.cpp create mode 100644 unittests/debugserver/debugserver_LogCallback.cpp create mode 100644 unittests/gtest_common.h create mode 100644 unittests/tools/CMakeLists.txt create mode 100644 unittests/tools/lldb-server/CMakeLists.txt create mode 100644 unittests/tools/lldb-server/inferior/thread_inferior.cpp create mode 100644 unittests/tools/lldb-server/tests/CMakeLists.txt create mode 100644 unittests/tools/lldb-server/tests/MessageObjects.cpp create mode 100644 unittests/tools/lldb-server/tests/MessageObjects.h create mode 100644 unittests/tools/lldb-server/tests/TestClient.cpp create mode 100644 unittests/tools/lldb-server/tests/TestClient.h create mode 100644 unittests/tools/lldb-server/tests/ThreadIdsInJstopinfoTest.cpp create mode 100644 use_lldb_suite_root.py create mode 100755 utils/git-svn/convert.py create mode 100644 utils/lui/Readme create mode 100644 utils/lui/breakwin.py create mode 100644 utils/lui/commandwin.py create mode 100755 utils/lui/cui.py create mode 100644 utils/lui/debuggerdriver.py create mode 100644 utils/lui/eventwin.py create mode 100644 utils/lui/lldbutil.py create mode 100755 utils/lui/lui.py create mode 100755 utils/lui/sandbox.py create mode 100644 utils/lui/sourcewin.py create mode 100644 utils/lui/statuswin.py create mode 100755 utils/misc/grep-svn-log.py create mode 100644 utils/sync-source/README.txt create mode 100644 utils/sync-source/lib/transfer/__init__.py create mode 100644 utils/sync-source/lib/transfer/protocol.py create mode 100644 utils/sync-source/lib/transfer/rsync.py create mode 100644 utils/sync-source/lib/transfer/transfer_spec.py create mode 100644 utils/sync-source/pylintrc create mode 100644 utils/sync-source/syncsource.py create mode 100644 utils/test/README-disasm create mode 100644 utils/test/README-lldb-disasm create mode 100644 utils/test/README-run-until-faulted create mode 100755 utils/test/disasm.py create mode 100755 utils/test/lldb-disasm.py create mode 100755 utils/test/llvm-mc-shell.py create mode 100644 utils/test/main.c create mode 100755 utils/test/ras.py create mode 100755 utils/test/run-dis.py create mode 100755 utils/test/run-until-faulted.py create mode 100644 utils/vim-lldb/README create mode 100644 utils/vim-lldb/doc/lldb.txt create mode 100644 utils/vim-lldb/plugin/lldb.vim create mode 100644 utils/vim-lldb/python-vim-lldb/import_lldb.py create mode 100644 utils/vim-lldb/python-vim-lldb/lldb_controller.py create mode 100644 utils/vim-lldb/python-vim-lldb/plugin.py create mode 100644 utils/vim-lldb/python-vim-lldb/vim_panes.py create mode 100644 utils/vim-lldb/python-vim-lldb/vim_signs.py create mode 100644 utils/vim-lldb/python-vim-lldb/vim_ui.py diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 000000000..e8fa2aaf0 --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "project_id" : "lldb", + "conduit_uri" : "https://reviews.llvm.org/" +} diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..9b3aa8b72 --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: LLVM diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..29f407fb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +#==============================================================================# +# The file specifies intentionally untracked files that git should ignore. +# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html +# +# This file is intentionally different from the output of `git svn show-ignore`, +# as most of those are useless. +#==============================================================================# + +#==============================================================================# +# File extensions to be ignored anywhere in the tree. +#==============================================================================# +# Temp files created by most text editors. +*~ +# Merge files created by git. +*.orig +# Byte compiled python modules. +*.pyc +*.pyproj +# pyenv settings +.python-version +*.sln +*.suo +# vim swap files +.*.swp +.sw? +# OS X specific files. +.DS_store +DerivedData/ + +# Remote build configuration files. +.remote-build.conf + +build/ +pyproj/ +llvm-build/ +ninja/ +*xcuserdata +test/20* +__pycache__/ +*.lock +*.so + +clang-module-cache + +# Skip ctags-style tags files +tags + +# We should ignore Xcode-style embedding of llvm/ at lldb root dir. +# Do not add trailing '/'s, they skip symlinks. +/llvm +/DerivedData + +# Ignore test trace directories. +20??-??-??-??_??_??/ + +# Ignore crashlog support files. +crashinfo.lock +crashinfo.so + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..ada293811 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 3.4.3) + +# Add path for custom modules +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" + ) + +include(LLDBStandalone) +include(LLDBConfig) +include(AddLLDB) + +if (CMAKE_SYSTEM_NAME MATCHES "Windows|Android") + set(LLDB_DEFAULT_DISABLE_LIBEDIT 1) +else() + set(LLDB_DEFAULT_DISABLE_LIBEDIT 0) +endif () + +# We need libedit support to go down both the source and +# the scripts directories. +set(LLDB_DISABLE_LIBEDIT ${LLDB_DEFAULT_DISABLE_LIBEDIT} CACHE BOOL "Disables the use of editline.") +if (LLDB_DISABLE_LIBEDIT) + add_definitions( -DLLDB_DISABLE_LIBEDIT ) +endif() + +# add_subdirectory(include) +add_subdirectory(docs) +if (NOT LLDB_DISABLE_PYTHON) + if(LLDB_USE_SYSTEM_SIX) + set(SIX_EXTRA_ARGS "--useSystemSix") + endif() + + set(LLDB_PYTHON_TARGET_DIR ${LLDB_BINARY_DIR}/scripts) + if(LLDB_BUILD_FRAMEWORK) + set(LLDB_PYTHON_TARGET_DIR + ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${LLDB_FRAMEWORK_INSTALL_DIR}) + else() + # Don't set -m when building the framework. + set(FINISH_EXTRA_ARGS "-m") + endif() + set(LLDB_WRAP_PYTHON ${LLDB_BINARY_DIR}/scripts/LLDBWrapPython.cpp) + + add_subdirectory(scripts) +endif () +add_subdirectory(source) +add_subdirectory(test) +add_subdirectory(tools) +add_subdirectory(unittests) +add_subdirectory(lit) + +if (NOT LLDB_DISABLE_PYTHON) + # Add a Post-Build Event to copy over Python files and create the symlink + # to liblldb.so for the Python API(hardlink on Windows) + add_custom_target(finish_swig ALL + COMMAND + ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/finishSwigWrapperClasses.py + --srcRoot=${LLDB_SOURCE_DIR} + --targetDir=${LLDB_PYTHON_TARGET_DIR} + --cfgBldDir=${CMAKE_CURRENT_BINARY_DIR}/scripts + --prefix=${CMAKE_BINARY_DIR} + --cmakeBuildConfiguration=${CMAKE_CFG_INTDIR} + --lldbLibDir=lib${LLVM_LIBDIR_SUFFIX} + ${SIX_EXTRA_ARGS} + ${FINISH_EXTRA_ARGS} + VERBATIM + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/finishSwigWrapperClasses.py + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/scripts/lldb.py + COMMENT "Python script sym-linking LLDB Python API") + # We depend on liblldb being built before we can do this step. + add_dependencies(finish_swig liblldb lldb-argdumper) + + # If we build the readline module, we depend on that happening + # first. + if (TARGET readline) + add_dependencies(finish_swig readline) + endif() + + # Ensure we do the python post-build step when building lldb. + add_dependencies(lldb finish_swig) + + if(LLDB_BUILD_FRAMEWORK) + # The target to install libLLDB needs to depend on finish swig so that the + # framework build properly copies over the Python files. + add_dependencies(install-liblldb finish_swig) + endif() + + # Add a Post-Build Event to copy the custom Python DLL to the lldb binaries dir so that Windows can find it when launching + # lldb.exe or any other executables that were linked with liblldb. + if (WIN32 AND NOT "${PYTHON_DLL}" STREQUAL "") + # When using the Visual Studio CMake generator the lldb binaries end up in Release/bin, Debug/bin etc. + file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin" LLDB_BIN_DIR) + file(TO_NATIVE_PATH "${PYTHON_DLL}" PYTHON_DLL_NATIVE_PATH) + add_custom_command( + TARGET finish_swig + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_DLL_NATIVE_PATH} ${LLDB_BIN_DIR} VERBATIM + COMMENT "Copying Python DLL to LLDB binaries directory.") + endif () +endif () diff --git a/CODE_OWNERS.txt b/CODE_OWNERS.txt new file mode 100644 index 000000000..8fe43284c --- /dev/null +++ b/CODE_OWNERS.txt @@ -0,0 +1,55 @@ +This file is a list of the people responsible for ensuring that patches for a +particular part of LLDB are reviewed, either by themself or by someone else. +They are also the gatekeepers for their part of LLDB, with the final word on +what goes in or not. + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). + +N: Sean Callanan +E: scallanan@apple.com +D: Expression evaluator, IR interpreter, Clang integration + +N: Greg Clayton +E: clayborg@gmail.com +D: Overall LLDB architecture, Host (common+macosx), Symbol, API, ABI, Mac-specific code, +D: DynamicLoader, ObjectFile, IOHandler, EditLine, Core/Value*, Watchpoints, debugserver +D: Build scripts, Test suite, Platform, gdb-remote, Anything not covered by this file + +N: Jim Ingham +E: jingham@apple.com +D: Overall LLDB architecture, Thread plans, Expression parser, ValueObject, Breakpoints, ABI +D: Watchpoints, Trampolines, Target, Command Interpreter, C++ / Objective C Language runtime +D: Data Formatters + +N: Ilia K +E: ki.stfu@gmail.com +D: lldb-mi + +N: Ed Maste +E: emaste@freebsd.org +D: FreeBSD + +N: Jason Molenda +E: jmolenda@apple.com +D: ABI, Disassembler, Unwinding, iOS, debugserver, Platform, ObjectFile, SymbolFile, +D: SymbolVendor, DWARF, gdb-remote + +N: Hafiz Abid Qadeer +E: abidh.haq@gmail.com +D: lldb-mi + +N: Kamil Rytarowski +E: kamil@netbsd.org +D: NetBSD + +N: Zachary Turner +E: zturner@google.com +D: CMake build, Host (common+windows), Plugins/Process/Windows, Anything Windows-specific +D: Test suite + +N: Pavel Labath +E: labath@google.com +D: Linux, Android diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 000000000..ef7126994 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,18 @@ +LLDB Installation Instructions +============================== + +LLDB builds on Mac OS X (with Xcode) and Linux (with GCC or Clang). + +On Mac OS X, in addition to using Xcode you'll need to enable code signing +on your system to either build lldb or debug using lldb. Please see the code +signing documentation in docs/code-signing.txt for more detailed directions. + +If you are building on Mac OS X and LLVM is not present in llvm/, then LLDB +will check it out automatically. The files in scripts/Xcode/repos determine +which branches of LLVM/Clang are checked out, depending on the current +LLDB branch, according to the algorithm in scripts/Xcode/repo.py. + +For instructions to build LLDB on Linux, or more details about supported +compiler versions, other dependencies, and build flags, see: + + http://lldb.llvm.org/build.html diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 000000000..1f0309419 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,38 @@ +University of Illinois/NCSA +Open Source License + +Copyright (c) 2010 Apple Inc. +All rights reserved. + +Developed by: + + LLDB Team + + http://lldb.llvm.org/ + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLDB Team, copyright holders, nor the names of + its contributors may be used to endorse or promote products derived from + this Software without specific prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + diff --git a/cmake/LLDBDependencies.cmake b/cmake/LLDBDependencies.cmake new file mode 100644 index 000000000..55ce37908 --- /dev/null +++ b/cmake/LLDBDependencies.cmake @@ -0,0 +1,52 @@ +set(LLDB_SYSTEM_LIBS) + +# Windows-only libraries +if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) + list(APPEND LLDB_SYSTEM_LIBS + ws2_32 + rpcrt4 + ) +endif () + +if (NOT LLDB_DISABLE_LIBEDIT) + list(APPEND LLDB_SYSTEM_LIBS edit) +endif() +if (NOT LLDB_DISABLE_CURSES) + list(APPEND LLDB_SYSTEM_LIBS ${CURSES_LIBRARIES}) + if(LLVM_ENABLE_TERMINFO AND HAVE_TERMINFO) + list(APPEND LLDB_SYSTEM_LIBS ${TERMINFO_LIBS}) + endif() +endif() + +if (NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB ) + list(APPEND LLDB_SYSTEM_LIBS atomic) +endif() + +list(APPEND LLDB_SYSTEM_LIBS ${Backtrace_LIBRARY}) + +if (NOT LLDB_DISABLE_PYTHON AND NOT LLVM_BUILD_STATIC) + list(APPEND LLDB_SYSTEM_LIBS ${PYTHON_LIBRARIES}) +endif() + +list(APPEND LLDB_SYSTEM_LIBS ${system_libs}) + +if (LLVM_BUILD_STATIC) + if (NOT LLDB_DISABLE_PYTHON) + list(APPEND LLDB_SYSTEM_LIBS python2.7 util) + endif() + if (NOT LLDB_DISABLE_CURSES) + list(APPEND LLDB_SYSTEM_LIBS gpm) + endif() +endif() + +if ( NOT LLDB_DISABLE_PYTHON ) + set_source_files_properties(${LLDB_WRAP_PYTHON} PROPERTIES GENERATED 1) + if (CLANG_CL) + set_source_files_properties(${LLDB_WRAP_PYTHON} PROPERTIES COMPILE_FLAGS -Wno-unused-function) + endif() + if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND + NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") + set_property(SOURCE ${LLDB_WRAP_PYTHON} + APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-sequence-point -Wno-cast-qual") + endif () +endif() diff --git a/cmake/XcodeHeaderGenerator/CMakeLists.txt b/cmake/XcodeHeaderGenerator/CMakeLists.txt new file mode 100644 index 000000000..f515c5fb8 --- /dev/null +++ b/cmake/XcodeHeaderGenerator/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.4.3) + +project(XcodeConfig C CXX) + +set(CMAKE_MODULE_PATH + ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/.." + "${CMAKE_CURRENT_SOURCE_DIR}/../modules" + ) + +set(LLDB_CONFIG_HEADER_INPUT + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/lldb/Host/Config.h.cmake) + +include(LLDBGenerateConfig) diff --git a/cmake/modules/AddLLDB.cmake b/cmake/modules/AddLLDB.cmake new file mode 100644 index 000000000..4c6f1efd6 --- /dev/null +++ b/cmake/modules/AddLLDB.cmake @@ -0,0 +1,163 @@ +function(add_lldb_library name) + # only supported parameters to this macro are the optional + # MODULE;SHARED;STATIC library type and source files + cmake_parse_arguments(PARAM + "MODULE;SHARED;STATIC;OBJECT;PLUGIN" + "" + "DEPENDS;LINK_LIBS;LINK_COMPONENTS" + ${ARGN}) + llvm_process_sources(srcs ${PARAM_UNPARSED_ARGUMENTS}) + list(APPEND LLVM_LINK_COMPONENTS ${PARAM_LINK_COMPONENTS}) + + if(PARAM_PLUGIN) + set_property(GLOBAL APPEND PROPERTY LLDB_PLUGINS ${name}) + endif() + + if (MSVC_IDE OR XCODE) + string(REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR}) + list(GET split_path -1 dir) + file(GLOB_RECURSE headers + ../../include/lldb${dir}/*.h) + set(srcs ${srcs} ${headers}) + endif() + if (PARAM_MODULE) + set(libkind MODULE) + elseif (PARAM_SHARED) + set(libkind SHARED) + elseif (PARAM_OBJECT) + set(libkind OBJECT) + else () + # PARAM_STATIC or library type unspecified. BUILD_SHARED_LIBS + # does not control the kind of libraries created for LLDB, + # only whether or not they link to shared/static LLVM/Clang + # libraries. + set(libkind STATIC) + endif() + + #PIC not needed on Win + if (NOT WIN32) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + endif() + + if (PARAM_OBJECT) + add_library(${name} ${libkind} ${srcs}) + else() + llvm_add_library(${name} ${libkind} ${srcs} LINK_LIBS + ${PARAM_LINK_LIBS} + DEPENDS ${PARAM_DEPENDS}) + + if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "liblldb") + if (PARAM_SHARED) + set(out_dir lib${LLVM_LIBDIR_SUFFIX}) + if(${name} STREQUAL "liblldb" AND LLDB_BUILD_FRAMEWORK) + set(out_dir ${LLDB_FRAMEWORK_INSTALL_DIR}) + endif() + install(TARGETS ${name} + COMPONENT ${name} + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${out_dir} + ARCHIVE DESTINATION ${out_dir}) + else() + install(TARGETS ${name} + COMPONENT ${name} + LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} + ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}) + endif() + if (NOT CMAKE_CONFIGURATION_TYPES) + add_custom_target(install-${name} + DEPENDS ${name} + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=${name} + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") + endif() + endif() + endif() + + # Hack: only some LLDB libraries depend on the clang autogenerated headers, + # but it is simple enough to make all of LLDB depend on some of those + # headers without negatively impacting much of anything. + get_property(CLANG_TABLEGEN_TARGETS GLOBAL PROPERTY CLANG_TABLEGEN_TARGETS) + if(CLANG_TABLEGEN_TARGETS) + add_dependencies(${name} ${CLANG_TABLEGEN_TARGETS}) + endif() + + set_target_properties(${name} PROPERTIES FOLDER "lldb libraries") +endfunction(add_lldb_library) + +function(add_lldb_executable name) + cmake_parse_arguments(ARG + "INCLUDE_IN_FRAMEWORK;GENERATE_INSTALL" + "" + "LINK_LIBS;LINK_COMPONENTS" + ${ARGN} + ) + + list(APPEND LLVM_LINK_COMPONENTS ${ARG_LINK_COMPONENTS}) + add_llvm_executable(${name} ${ARG_UNPARSED_ARGUMENTS}) + + target_link_libraries(${name} ${ARG_LINK_LIBS}) + set_target_properties(${name} PROPERTIES + FOLDER "lldb executables") + + if(LLDB_BUILD_FRAMEWORK) + if(ARG_INCLUDE_IN_FRAMEWORK) + string(REGEX REPLACE "[^/]+" ".." _dots ${LLDB_FRAMEWORK_INSTALL_DIR}) + set_target_properties(${name} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY $/Resources + BUILD_WITH_INSTALL_RPATH On + INSTALL_RPATH "@loader_path/../../../../${_dots}/${LLDB_FRAMEWORK_INSTALL_DIR}") + # For things inside the framework we don't need functional install targets + # because CMake copies the resources and headers from the build directory. + # But we still need this target to exist in order to use the + # LLVM_DISTRIBUTION_COMPONENTS build option. We also need the + # install-liblldb target to depend on this tool, so that it gets put into + # the Resources directory before the framework is installed. + if(ARG_GENERATE_INSTALL) + add_custom_target(install-${name} DEPENDS ${name}) + add_dependencies(install-liblldb ${name}) + endif() + else() + set_target_properties(${name} PROPERTIES + BUILD_WITH_INSTALL_RPATH On + INSTALL_RPATH "@loader_path/../${LLDB_FRAMEWORK_INSTALL_DIR}") + endif() + endif() + + if(ARG_GENERATE_INSTALL AND NOT (ARG_INCLUDE_IN_FRAMEWORK AND LLDB_BUILD_FRAMEWORK )) + install(TARGETS ${name} + COMPONENT ${name} + RUNTIME DESTINATION bin) + if (NOT CMAKE_CONFIGURATION_TYPES) + add_custom_target(install-${name} + DEPENDS ${name} + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=${name} + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") + endif() + endif() + + if(ARG_INCLUDE_IN_FRAMEWORK AND LLDB_BUILD_FRAMEWORK) + add_llvm_tool_symlink(${name} ${name} ALWAYS_GENERATE SKIP_INSTALL + OUTPUT_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) + endif() +endfunction(add_lldb_executable) + +function(add_lldb_tool name) + add_lldb_executable(${name} GENERATE_INSTALL ${ARGN}) +endfunction() + +# Support appending linker flags to an existing target. +# This will preserve the existing linker flags on the +# target, if there are any. +function(lldb_append_link_flags target_name new_link_flags) + # Retrieve existing linker flags. + get_target_property(current_link_flags ${target_name} LINK_FLAGS) + + # If we had any linker flags, include them first in the new linker flags. + if(current_link_flags) + set(new_link_flags "${current_link_flags} ${new_link_flags}") + endif() + + # Now set them onto the target. + set_target_properties(${target_name} PROPERTIES LINK_FLAGS ${new_link_flags}) +endfunction() diff --git a/cmake/modules/EmbedAppleVersion.cmake b/cmake/modules/EmbedAppleVersion.cmake new file mode 100644 index 000000000..57f5eba45 --- /dev/null +++ b/cmake/modules/EmbedAppleVersion.cmake @@ -0,0 +1,11 @@ +execute_process(COMMAND /usr/libexec/PlistBuddy -c "Print:CFBundleVersion" ${LLDB_INFO_PLIST} + OUTPUT_VARIABLE BundleVersion + OUTPUT_STRIP_TRAILING_WHITESPACE) + +file(APPEND "${HEADER_FILE}.tmp" + "#define LLDB_VERSION_STRING lldb-${BundleVersion}\n") + +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${HEADER_FILE}.tmp" "${HEADER_FILE}") + +file(REMOVE "${HEADER_FILE}.tmp") diff --git a/cmake/modules/LLDBConfig.cmake b/cmake/modules/LLDBConfig.cmake new file mode 100644 index 000000000..726552675 --- /dev/null +++ b/cmake/modules/LLDBConfig.cmake @@ -0,0 +1,415 @@ +include(CheckCXXSymbolExists) + +set(LLDB_PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) +set(LLDB_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/source") +set(LLDB_INCLUDE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/include") + +set(LLDB_LINKER_SUPPORTS_GROUPS OFF) +if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") + # The Darwin linker doesn't understand --start-group/--end-group. + set(LLDB_LINKER_SUPPORTS_GROUPS ON) +endif() + +set(LLDB_DEFAULT_DISABLE_PYTHON 0) +set(LLDB_DEFAULT_DISABLE_CURSES 0) + +if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) + set(LLDB_DEFAULT_DISABLE_CURSES 1) +elseif (CMAKE_SYSTEM_NAME MATCHES "Android" ) + set(LLDB_DEFAULT_DISABLE_PYTHON 1) + set(LLDB_DEFAULT_DISABLE_CURSES 1) +elseif(IOS) + set(LLDB_DEFAULT_DISABLE_PYTHON 1) +endif() + +if(IOS) + add_definitions(-DNO_XPC_SERVICES) +endif() + +set(LLDB_DISABLE_PYTHON ${LLDB_DEFAULT_DISABLE_PYTHON} CACHE BOOL + "Disables the Python scripting integration.") +set(LLDB_DISABLE_CURSES ${LLDB_DEFAULT_DISABLE_CURSES} CACHE BOOL + "Disables the Curses integration.") + +set(LLDB_RELOCATABLE_PYTHON 0 CACHE BOOL + "Causes LLDB to use the PYTHONHOME environment variable to locate Python.") + +set(LLDB_USE_SYSTEM_SIX 0 CACHE BOOL + "Use six.py shipped with system and do not install a copy of it") + +if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") + set(LLDB_EXPORT_ALL_SYMBOLS 0 CACHE BOOL + "Causes lldb to export all symbols when building liblldb.") +else() + # Windows doesn't support toggling this, so don't bother making it a + # cache variable. + set(LLDB_EXPORT_ALL_SYMBOLS 0) +endif() + +if ((NOT MSVC) OR MSVC12) + add_definitions( -DHAVE_ROUND ) +endif() + +if (LLDB_DISABLE_CURSES) + add_definitions( -DLLDB_DISABLE_CURSES ) +endif() + +# On Windows, we can't use the normal FindPythonLibs module that comes with CMake, +# for a number of reasons. +# 1) Prior to MSVC 2015, it is only possible to embed Python if python itself was +# compiled with an identical version (and build configuration) of MSVC as LLDB. +# The standard algorithm does not take into account the differences between +# a binary release distribution of python and a custom built distribution. +# 2) From MSVC 2015 and onwards, it is only possible to use Python 3.5 or later. +# 3) FindPythonLibs queries the registry to locate Python, and when looking for a +# 64-bit version of Python, since cmake.exe is a 32-bit executable, it will see +# a 32-bit view of the registry. As such, it is impossible for FindPythonLibs to +# locate 64-bit Python libraries. +# This function is designed to address those limitations. Currently it only partially +# addresses them, but it can be improved and extended on an as-needed basis. +function(find_python_libs_windows) + if ("${PYTHON_HOME}" STREQUAL "") + message("LLDB embedded Python on Windows requires specifying a value for PYTHON_HOME. Python support disabled.") + set(LLDB_DISABLE_PYTHON 1 PARENT_SCOPE) + return() + endif() + + file(TO_CMAKE_PATH "${PYTHON_HOME}/Include" PYTHON_INCLUDE_DIRS) + + if(EXISTS "${PYTHON_INCLUDE_DIRS}/patchlevel.h") + file(STRINGS "${PYTHON_INCLUDE_DIRS}/patchlevel.h" python_version_str + REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") + string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"+]+)[+]?\".*" "\\1" + PYTHONLIBS_VERSION_STRING "${python_version_str}") + message("-- Found Python version ${PYTHONLIBS_VERSION_STRING}") + string(REGEX REPLACE "([0-9]+)[.]([0-9]+)[.][0-9]+" "python\\1\\2" PYTHONLIBS_BASE_NAME "${PYTHONLIBS_VERSION_STRING}") + unset(python_version_str) + else() + message("Unable to find ${PYTHON_INCLUDE_DIRS}/patchlevel.h, Python installation is corrupt.") + message("Python support will be disabled for this build.") + set(LLDB_DISABLE_PYTHON 1 PARENT_SCOPE) + return() + endif() + + file(TO_CMAKE_PATH "${PYTHON_HOME}" PYTHON_HOME) + file(TO_CMAKE_PATH "${PYTHON_HOME}/python_d.exe" PYTHON_DEBUG_EXE) + file(TO_CMAKE_PATH "${PYTHON_HOME}/libs/${PYTHONLIBS_BASE_NAME}_d.lib" PYTHON_DEBUG_LIB) + file(TO_CMAKE_PATH "${PYTHON_HOME}/${PYTHONLIBS_BASE_NAME}_d.dll" PYTHON_DEBUG_DLL) + + file(TO_CMAKE_PATH "${PYTHON_HOME}/python.exe" PYTHON_RELEASE_EXE) + file(TO_CMAKE_PATH "${PYTHON_HOME}/libs/${PYTHONLIBS_BASE_NAME}.lib" PYTHON_RELEASE_LIB) + file(TO_CMAKE_PATH "${PYTHON_HOME}/${PYTHONLIBS_BASE_NAME}.dll" PYTHON_RELEASE_DLL) + + if (NOT EXISTS ${PYTHON_DEBUG_EXE}) + message("Unable to find ${PYTHON_DEBUG_EXE}") + unset(PYTHON_DEBUG_EXE) + endif() + + if (NOT EXISTS ${PYTHON_RELEASE_EXE}) + message("Unable to find ${PYTHON_RELEASE_EXE}") + unset(PYTHON_RELEASE_EXE) + endif() + + if (NOT EXISTS ${PYTHON_DEBUG_LIB}) + message("Unable to find ${PYTHON_DEBUG_LIB}") + unset(PYTHON_DEBUG_LIB) + endif() + + if (NOT EXISTS ${PYTHON_RELEASE_LIB}) + message("Unable to find ${PYTHON_RELEASE_LIB}") + unset(PYTHON_RELEASE_LIB) + endif() + + if (NOT EXISTS ${PYTHON_DEBUG_DLL}) + message("Unable to find ${PYTHON_DEBUG_DLL}") + unset(PYTHON_DEBUG_DLL) + endif() + + if (NOT EXISTS ${PYTHON_RELEASE_DLL}) + message("Unable to find ${PYTHON_RELEASE_DLL}") + unset(PYTHON_RELEASE_DLL) + endif() + + if (NOT (PYTHON_DEBUG_EXE AND PYTHON_RELEASE_EXE AND PYTHON_DEBUG_LIB AND PYTHON_RELEASE_LIB AND PYTHON_DEBUG_DLL AND PYTHON_RELEASE_DLL)) + message("Python installation is corrupt. Python support will be disabled for this build.") + set(LLDB_DISABLE_PYTHON 1 PARENT_SCOPE) + return() + endif() + + # Generator expressions are evaluated in the context of each build configuration generated + # by CMake. Here we use the $:VALUE logical generator expression to ensure + # that the debug Python library, DLL, and executable are used in the Debug build configuration. + # + # Generator expressions can be difficult to grok at first so here's a breakdown of the one + # used for PYTHON_LIBRARY: + # + # 1. $ evaluates to 1 when the Debug configuration is being generated, + # or 0 in all other cases. + # 2. $<$:${PYTHON_DEBUG_LIB}> expands to ${PYTHON_DEBUG_LIB} when the Debug + # configuration is being generated, or nothing (literally) in all other cases. + # 3. $<$>:${PYTHON_RELEASE_LIB}> expands to ${PYTHON_RELEASE_LIB} when + # any configuration other than Debug is being generated, or nothing in all other cases. + # 4. The conditionals in 2 & 3 are mutually exclusive. + # 5. A logical expression with a conditional that evaluates to 0 yields no value at all. + # + # Due to 4 & 5 it's possible to concatenate 2 & 3 to obtain a single value specific to each + # build configuration. In this example the value will be ${PYTHON_DEBUG_LIB} when generating the + # Debug configuration, or ${PYTHON_RELEASE_LIB} when generating any other configuration. + # Note that it's imperative that there is no whitespace between the two expressions, otherwise + # CMake will insert a semicolon between the two. + set (PYTHON_EXECUTABLE $<$:${PYTHON_DEBUG_EXE}>$<$>:${PYTHON_RELEASE_EXE}>) + set (PYTHON_LIBRARY $<$:${PYTHON_DEBUG_LIB}>$<$>:${PYTHON_RELEASE_LIB}>) + set (PYTHON_DLL $<$:${PYTHON_DEBUG_DLL}>$<$>:${PYTHON_RELEASE_DLL}>) + + set (PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} PARENT_SCOPE) + set (PYTHON_LIBRARY ${PYTHON_LIBRARY} PARENT_SCOPE) + set (PYTHON_DLL ${PYTHON_DLL} PARENT_SCOPE) + set (PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS} PARENT_SCOPE) + + message("-- LLDB Found PythonExecutable: ${PYTHON_RELEASE_EXE} and ${PYTHON_DEBUG_EXE}") + message("-- LLDB Found PythonLibs: ${PYTHON_RELEASE_LIB} and ${PYTHON_DEBUG_LIB}") + message("-- LLDB Found PythonDLL: ${PYTHON_RELEASE_DLL} and ${PYTHON_DEBUG_DLL}") + message("-- LLDB Found PythonIncludeDirs: ${PYTHON_INCLUDE_DIRS}") +endfunction(find_python_libs_windows) + +if (NOT LLDB_DISABLE_PYTHON) + + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + find_python_libs_windows() + + if (NOT LLDB_RELOCATABLE_PYTHON) + file(TO_CMAKE_PATH "${PYTHON_HOME}" LLDB_PYTHON_HOME) + add_definitions( -DLLDB_PYTHON_HOME="${LLDB_PYTHON_HOME}" ) + endif() + else() + find_package(PythonLibs REQUIRED) + endif() + + if (PYTHON_INCLUDE_DIRS) + include_directories(${PYTHON_INCLUDE_DIRS}) + endif() +endif() + +if (LLDB_DISABLE_PYTHON) + unset(PYTHON_INCLUDE_DIRS) + unset(PYTHON_LIBRARY) + add_definitions( -DLLDB_DISABLE_PYTHON ) +endif() + +if (LLVM_EXTERNAL_CLANG_SOURCE_DIR) + include_directories(${LLVM_EXTERNAL_CLANG_SOURCE_DIR}/include) +else () + include_directories(${CMAKE_SOURCE_DIR}/tools/clang/include) +endif () +include_directories("${CMAKE_CURRENT_BINARY_DIR}/../clang/include") + +# Disable GCC warnings +check_cxx_compiler_flag("-Wno-deprecated-declarations" + CXX_SUPPORTS_NO_DEPRECATED_DECLARATIONS) +if (CXX_SUPPORTS_NO_DEPRECATED_DECLARATIONS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") +endif () + +check_cxx_compiler_flag("-Wno-unknown-pragmas" + CXX_SUPPORTS_NO_UNKNOWN_PRAGMAS) +if (CXX_SUPPORTS_NO_UNKNOWN_PRAGMAS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") +endif () + +check_cxx_compiler_flag("-Wno-strict-aliasing" + CXX_SUPPORTS_NO_STRICT_ALIASING) +if (CXX_SUPPORTS_NO_STRICT_ALIASING) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing") +endif () + +# Disable Clang warnings +check_cxx_compiler_flag("-Wno-deprecated-register" + CXX_SUPPORTS_NO_DEPRECATED_REGISTER) +if (CXX_SUPPORTS_NO_DEPRECATED_REGISTER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register") +endif () + +check_cxx_compiler_flag("-Wno-vla-extension" + CXX_SUPPORTS_NO_VLA_EXTENSION) +if (CXX_SUPPORTS_NO_VLA_EXTENSION) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-vla-extension") +endif () + +# Disable MSVC warnings +if( MSVC ) + add_definitions( + -wd4018 # Suppress 'warning C4018: '>=' : signed/unsigned mismatch' + -wd4068 # Suppress 'warning C4068: unknown pragma' + -wd4150 # Suppress 'warning C4150: deletion of pointer to incomplete type' + -wd4251 # Suppress 'warning C4251: T must have dll-interface to be used by clients of class U.' + -wd4521 # Suppress 'warning C4521: 'type' : multiple copy constructors specified' + -wd4530 # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.' + ) +endif() + +# Use the Unicode (UTF-16) APIs by default on Win32 +if (CMAKE_SYSTEM_NAME MATCHES "Windows") + add_definitions( -D_UNICODE -DUNICODE ) +endif() + +set(LLDB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LLDB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite " +"the makefiles distributed with LLDB. Please create a directory and run cmake " +"from there, passing the path to this source directory as the last argument. " +"This process created the file `CMakeCache.txt' and the directory " +"`CMakeFiles'. Please delete them.") +endif() + +# Compute the LLDB version from the LLVM version. +string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLDB_VERSION + ${PACKAGE_VERSION}) +message(STATUS "LLDB version: ${LLDB_VERSION}") + +include_directories(BEFORE + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_BINARY_DIR}/include + ) + +if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) + install(DIRECTORY include/ + COMPONENT lldb_headers + DESTINATION include + FILES_MATCHING + PATTERN "*.h" + PATTERN ".svn" EXCLUDE + PATTERN ".cmake" EXCLUDE + PATTERN "Config.h" EXCLUDE + ) + + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ + COMPONENT lldb_headers + DESTINATION include + FILES_MATCHING + PATTERN "*.h" + PATTERN ".svn" EXCLUDE + PATTERN ".cmake" EXCLUDE + ) +endif() + +if (NOT LIBXML2_FOUND AND NOT (CMAKE_SYSTEM_NAME MATCHES "Windows")) + # Skip Libxml2 on Windows. In CMake 3.4 and higher, the algorithm for + # finding libxml2 got "smarter", and it can now locate the version which is + # in gnuwin32, even though that version does not contain the headers that + # LLDB uses. + find_package(LibXml2) +endif() + +# Find libraries or frameworks that may be needed +if (APPLE) + if(NOT IOS) + find_library(CARBON_LIBRARY Carbon) + find_library(CORE_SERVICES_LIBRARY CoreServices) + find_library(DEBUG_SYMBOLS_LIBRARY DebugSymbols PATHS "/System/Library/PrivateFrameworks") + endif() + find_library(FOUNDATION_LIBRARY Foundation) + find_library(CORE_FOUNDATION_LIBRARY CoreFoundation) + find_library(SECURITY_LIBRARY Security) + + set(LLDB_FRAMEWORK_INSTALL_DIR Library/Frameworks CACHE STRING "Output directory for LLDB.framework") + set(LLDB_FRAMEWORK_VERSION A CACHE STRING "LLDB.framework version (default is A)") + set(LLDB_FRAMEWORK_RESOURCE_DIR + LLDB.framework/Versions/${LLDB_FRAMEWORK_VERSION}/Resources) + + add_definitions( -DLIBXML2_DEFINED ) + list(APPEND system_libs xml2 + ${CURSES_LIBRARIES} + ${FOUNDATION_LIBRARY} + ${CORE_FOUNDATION_LIBRARY} + ${CORE_SERVICES_LIBRARY} + ${SECURITY_LIBRARY} + ${DEBUG_SYMBOLS_LIBRARY}) + +else() + if (LIBXML2_FOUND) + add_definitions( -DLIBXML2_DEFINED ) + list(APPEND system_libs ${LIBXML2_LIBRARIES}) + include_directories(${LIBXML2_INCLUDE_DIR}) + endif() + +endif() + +if (HAVE_LIBPTHREAD) + list(APPEND system_libs pthread) +endif(HAVE_LIBPTHREAD) + +if (HAVE_LIBDL) + list(APPEND system_libs ${CMAKE_DL_LIBS}) +endif() + +# Figure out if lldb could use lldb-server. If so, then we'll +# ensure we build lldb-server when an lldb target is being built. +if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD") + set(LLDB_CAN_USE_LLDB_SERVER 1) +else() + set(LLDB_CAN_USE_LLDB_SERVER 0) +endif() + +# Figure out if lldb could use debugserver. If so, then we'll +# ensure we build debugserver when we build lldb. +if ( CMAKE_SYSTEM_NAME MATCHES "Darwin" ) + set(LLDB_CAN_USE_DEBUGSERVER 1) +else() + set(LLDB_CAN_USE_DEBUGSERVER 0) +endif() + +if (NOT LLDB_DISABLE_CURSES) + find_package(Curses REQUIRED) + + find_library(CURSES_PANEL_LIBRARY NAMES panel DOC "The curses panel library") + if (NOT CURSES_PANEL_LIBRARY) + message(FATAL_ERROR "A required curses' panel library not found.") + endif () + + # Add panels to the library path + set (CURSES_LIBRARIES ${CURSES_LIBRARIES} ${CURSES_PANEL_LIBRARY}) + + list(APPEND system_libs ${CURSES_LIBRARIES}) + include_directories(${CURSES_INCLUDE_DIR}) +endif () + +check_cxx_symbol_exists("__GLIBCXX__" "string" LLDB_USING_LIBSTDCXX) +if(LLDB_USING_LIBSTDCXX) + # There doesn't seem to be an easy way to check the library version. Instead, we rely on the + # fact that std::set did not have the allocator constructor available until version 4.9 + check_cxx_source_compiles(" + #include + std::set s = std::set(std::allocator()); + int main() { return 0; }" + LLDB_USING_LIBSTDCXX_4_9) + if (NOT LLDB_USING_LIBSTDCXX_4_9 AND NOT LLVM_ENABLE_EH) + message(WARNING + "You appear to be linking to libstdc++ version lesser than 4.9 without exceptions " + "enabled. These versions of the library have an issue, which causes occasional " + "lldb crashes. See for " + "details. Possible courses of action are:\n" + "- use libstdc++ version 4.9 or newer\n" + "- use libc++ (via LLVM_ENABLE_LIBCXX)\n" + "- enable exceptions (via LLVM_ENABLE_EH)\n" + "- ignore this warning and accept occasional instability") + endif() +endif() + +if(MSVC) + set(LLDB_USE_BUILTIN_DEMANGLER ON) +else() + option(LLDB_USE_BUILTIN_DEMANGLER "Use lldb's builtin demangler instead of the system one" ON) +endif() +if(LLDB_USE_BUILTIN_DEMANGLER) + add_definitions(-DLLDB_USE_BUILTIN_DEMANGLER) +endif() + +if ((CMAKE_SYSTEM_NAME MATCHES "Android") AND LLVM_BUILD_STATIC AND + ((ANDROID_ABI MATCHES "armeabi") OR (ANDROID_ABI MATCHES "mips"))) + add_definitions(-DANDROID_USE_ACCEPT_WORKAROUND) +endif() + +find_package(Backtrace) +include(LLDBGenerateConfig) diff --git a/cmake/modules/LLDBGenerateConfig.cmake b/cmake/modules/LLDBGenerateConfig.cmake new file mode 100644 index 000000000..d3d0cb220 --- /dev/null +++ b/cmake/modules/LLDBGenerateConfig.cmake @@ -0,0 +1,44 @@ +# This file contains all the logic for running configure-time checks + +include(CheckSymbolExists) +include(CheckIncludeFile) +include(CheckIncludeFiles) + +set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) +check_symbol_exists(ppoll poll.h HAVE_PPOLL) +set(CMAKE_REQUIRED_DEFINITIONS) +check_symbol_exists(sigaction signal.h HAVE_SIGACTION) + +check_include_file(termios.h HAVE_TERMIOS_H) +check_include_files("sys/types.h;sys/event.h" HAVE_SYS_EVENT_H) + +check_cxx_source_compiles(" + #include + int main() { process_vm_readv(0, nullptr, 0, nullptr, 0, 0); return 0; }" + HAVE_PROCESS_VM_READV) +check_cxx_source_compiles(" + #include + int main() { return __NR_process_vm_readv; }" + HAVE_NR_PROCESS_VM_READV) + +# These checks exist in LLVM's configuration, so I want to match the LLVM names +# so that the check isn't duplicated, but we translate them into the LLDB names +# so that I don't have to change all the uses at the moment. +set(LLDB_CONFIG_TERMIOS_SUPPORTED ${HAVE_TERMIOS_H}) +if(NOT UNIX) + set(LLDB_DISABLE_POSIX 1) +endif() + +if(NOT LLDB_CONFIG_HEADER_INPUT) + set(LLDB_CONFIG_HEADER_INPUT ${LLDB_INCLUDE_ROOT}/lldb/Host/Config.h.cmake) +endif() + +if(NOT LLDB_CONFIG_HEADER_OUTPUT) + set(LLDB_CONFIG_HEADER_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/include/lldb/Host/Config.h) +endif() + +# This should be done at the end +configure_file( + ${LLDB_CONFIG_HEADER_INPUT} + ${LLDB_CONFIG_HEADER_OUTPUT} + ) diff --git a/cmake/modules/LLDBStandalone.cmake b/cmake/modules/LLDBStandalone.cmake new file mode 100644 index 000000000..2f959c91f --- /dev/null +++ b/cmake/modules/LLDBStandalone.cmake @@ -0,0 +1,135 @@ +# If we are not building as a part of LLVM, build LLDB as an +# standalone project, using LLVM as an external library: +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(lldb) + + if (POLICY CMP0022) + cmake_policy(SET CMP0022 NEW) # automatic when 2.8.12 is required + endif() + + option(LLVM_INSTALL_TOOLCHAIN_ONLY "Only include toolchain files in the 'install' target." OFF) + + # Rely on llvm-config. + set(CONFIG_OUTPUT) + find_program(LLVM_CONFIG "llvm-config") + if(LLVM_CONFIG) + message(STATUS "Found LLVM_CONFIG as ${LLVM_CONFIG}") + set(CONFIG_COMMAND ${LLVM_CONFIG} + "--assertion-mode" + "--bindir" + "--libdir" + "--includedir" + "--prefix" + "--src-root" + "--cmakedir") + execute_process( + COMMAND ${CONFIG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE CONFIG_OUTPUT + ) + if(NOT HAD_ERROR) + string(REGEX REPLACE + "[ \t]*[\r\n]+[ \t]*" ";" + CONFIG_OUTPUT ${CONFIG_OUTPUT}) + + else() + string(REPLACE ";" " " CONFIG_COMMAND_STR "${CONFIG_COMMAND}") + message(STATUS "${CONFIG_COMMAND_STR}") + message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}") + endif() + else() + message(FATAL_ERROR "llvm-config not found -- ${LLVM_CONFIG}") + endif() + + list(GET CONFIG_OUTPUT 0 ENABLE_ASSERTIONS) + list(GET CONFIG_OUTPUT 1 TOOLS_BINARY_DIR) + list(GET CONFIG_OUTPUT 2 LIBRARY_DIR) + list(GET CONFIG_OUTPUT 3 INCLUDE_DIR) + list(GET CONFIG_OUTPUT 4 LLVM_OBJ_ROOT) + list(GET CONFIG_OUTPUT 5 MAIN_SRC_DIR) + list(GET CONFIG_OUTPUT 6 LLVM_CMAKE_PATH) + + if(NOT MSVC_IDE) + set(LLVM_ENABLE_ASSERTIONS ${ENABLE_ASSERTIONS} + CACHE BOOL "Enable assertions") + # Assertions should follow llvm-config's. + mark_as_advanced(LLVM_ENABLE_ASSERTIONS) + endif() + + set(LLVM_TOOLS_BINARY_DIR ${TOOLS_BINARY_DIR} CACHE PATH "Path to llvm/bin") + set(LLVM_LIBRARY_DIR ${LIBRARY_DIR} CACHE PATH "Path to llvm/lib") + set(LLVM_MAIN_INCLUDE_DIR ${INCLUDE_DIR} CACHE PATH "Path to llvm/include") + set(LLVM_DIR ${LLVM_OBJ_ROOT}/cmake/modules/CMakeFiles CACHE PATH "Path to LLVM build tree CMake files") + set(LLVM_BINARY_DIR ${LLVM_OBJ_ROOT} CACHE PATH "Path to LLVM build tree") + set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree") + + find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} + NO_DEFAULT_PATH) + + set(LLVMCONFIG_FILE "${LLVM_CMAKE_PATH}/LLVMConfig.cmake") + if(EXISTS ${LLVMCONFIG_FILE}) + file(TO_CMAKE_PATH "${LLVM_CMAKE_PATH}" LLVM_CMAKE_PATH) + list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}") + include(${LLVMCONFIG_FILE}) + else() + message(FATAL_ERROR "Not found: ${LLVMCONFIG_FILE}") + endif() + + # They are used as destination of target generators. + set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) + set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) + if(WIN32 OR CYGWIN) + # DLL platform -- put DLLs into bin. + set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) + else() + set(LLVM_SHLIB_OUTPUT_INTDIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) + endif() + + include(AddLLVM) + include(HandleLLVMOptions) + include(CheckAtomic) + + if (PYTHON_EXECUTABLE STREQUAL "") + set(Python_ADDITIONAL_VERSIONS 3.5 3.4 3.3 3.2 3.1 3.0 2.7 2.6 2.5) + include(FindPythonInterp) + if( NOT PYTHONINTERP_FOUND ) + message(FATAL_ERROR + "Unable to find Python interpreter, required for builds and testing. + Please install Python or specify the PYTHON_EXECUTABLE CMake variable.") + endif() + else() + message("-- Found PythonInterp: ${PYTHON_EXECUTABLE}") + endif() + + # Import CMake library targets from LLVM and Clang. + include("${LLVM_OBJ_ROOT}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm/LLVMConfig.cmake") + # cmake/clang/ClangConfig.cmake is not created when LLVM and Cland are built together. + if (EXISTS "${LLVM_OBJ_ROOT}/lib${LLVM_LIBDIR_SUFFIX}/cmake/clang/ClangConfig.cmake") + include("${LLVM_OBJ_ROOT}/lib${LLVM_LIBDIR_SUFFIX}/cmake/clang/ClangConfig.cmake") + endif() + + set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}") + + set(LLVM_BINARY_DIR ${CMAKE_BINARY_DIR}) + + set(CMAKE_INCLUDE_CURRENT_DIR ON) + include_directories("${LLVM_BINARY_DIR}/include" "${LLVM_MAIN_INCLUDE_DIR}") + # Next three include directories are needed when llvm-config is located in build directory. + # LLVM and Cland are assumed to be built together + if (EXISTS "${LLVM_OBJ_ROOT}/include") + include_directories("${LLVM_OBJ_ROOT}/include") + endif() + if (EXISTS "${LLVM_MAIN_SRC_DIR}/tools/clang/include") + include_directories("${LLVM_MAIN_SRC_DIR}/tools/clang/include") + endif() + if (EXISTS "${LLVM_OBJ_ROOT}/tools/clang/include") + include_directories("${LLVM_OBJ_ROOT}/tools/clang/include") + endif() + link_directories("${LLVM_LIBRARY_DIR}") + + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) + + set(LLDB_BUILT_STANDALONE 1) +endif() diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt new file mode 100644 index 000000000..045e816b7 --- /dev/null +++ b/docs/CMakeLists.txt @@ -0,0 +1,41 @@ + +include(FindDoxygen) + +if(DOXYGEN_FOUND) + set(abs_top_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/..) + set(DOT dot) + set(PACKAGE_VERSION mainline) + set(abs_top_builddir ..) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY) + + add_custom_target(lldb-cpp-doc + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating LLDB C++ API reference with Doxygen" VERBATIM + ) +endif(DOXYGEN_FOUND) + +find_package(PythonInterp REQUIRED) +find_program(EPYDOC_EXECUTABLE NAMES epydoc epydoc.py) +if(EPYDOC_EXECUTABLE) + find_program(DOT_EXECUTABLE dot) + if(DOT_EXECUTABLE) + set(EPYDOC_OPTIONS ${EPYDOC_OPTIONS} --graph all --dotpath ${DOT_EXECUTABLE}) + endif() + set(DOC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/doc") + file(MAKE_DIRECTORY "${DOC_DIR}") + #set(ENV{PYTHONPATH} ${CMAKE_CURRENT_BINARY_DIR}/../../../lib/python2.7/site-packages) + add_custom_target(lldb-python-doc + ${EPYDOC_EXECUTABLE} + --html + lldb + -o ${CMAKE_CURRENT_BINARY_DIR}/python_reference + --name "LLDB python API" + --url "http://lldb.llvm.org" + ${EPYDOC_OPTIONS} + DEPENDS swig_wrapper liblldb + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../lib${LLVM_LIBDIR_SUFFIX}/python2.7/site-packages + COMMENT "Generating LLDB Python API reference with epydoc" VERBATIM + ) +endif(EPYDOC_EXECUTABLE) diff --git a/docs/building-with-debug-llvm.txt b/docs/building-with-debug-llvm.txt new file mode 100644 index 000000000..f59ca410e --- /dev/null +++ b/docs/building-with-debug-llvm.txt @@ -0,0 +1,50 @@ +This document describes how to build a debug version of LLVM for use with +LLDB, and how to make LLDB use it. + +It assumes that you are using the Xcode 3 series (I used 3.2.4) to build +LLDB. It also assumes that your shell is /bin/bash, and that you are +currently at a shell prompt in a checked-out LLDB repository. + +1. Check out LLVM and Clang from their repositories. To determine + the revision to use, consult scripts/build-llvm.pl (this is done + in the first command line below). !!! WARNING Do not use the + name "llvm" for your checkout, for reasons described in part 3 + below. + + $ export CLANG_REVISION=`cat scripts/build-llvm.pl | grep ^our.*llvm_revision | cut -d \' -f 2,2` + $ svn co -r $CLANG_REVISION http://llvm.org/svn/llvm-project/llvm/trunk llvm.checkout + $ svn co -r $CLANG_REVISION http://llvm.org/svn/llvm-project/cfe/trunk llvm.checkout/tools/clang + +2. Configure LLVM/Clang with the proper options and compilers. I use: + + $ cd llvm.checkout + $ CC="cc -g -O0" CXX="c++ -g -O0" ./configure --disable-optimized --enable-assertions --enable-targets=x86_64,arm + $ CC="cc -g -O0" CXX="c++ -g -O0" make -j 2 + $ cd .. + +3. Create a link to the built LLVM. !!! WARNING: Do not rename the + directory! The LLVM builder script that runs as part of the Xcode + build keys off the fact that llvm/ is a symlink to recognize that + we are building with a custom debug build. + + $ ln -sf llvm.checkout llvm + +4. Make sure that your Xcode project is set up correctly. Open + lldb.xcodeproj and do the following: + + Under "Targets" in the Groups & Files navigator, double-click + lldb-tool. In the resulting window, select "Debug" from the + "Configuration:" drop-down. Then, make sure that the setting + "Build Active Architecture Only" is enabled. Close the window. + + Under "Targets" in the Groups & Files navigator, double-click + LLDB. In the resulting window, select "Debug" from the + "Configuration:" drop-down. Then, make sure that the setting + "Build Active Architecture Only" is enabled. Close the window. + +5. Ensure that Xcode is building the lldb-tool target in Debug + configuration for your architecture (typically x86_64). You + can usually pick these options from the Overview drop-down at + the top left of the Xcode window. + +6. Build lldb.xcodeproj. diff --git a/docs/code-signing.txt b/docs/code-signing.txt new file mode 100644 index 000000000..5407fd4bb --- /dev/null +++ b/docs/code-signing.txt @@ -0,0 +1,61 @@ +On MacOSX lldb needs to be code signed. The Debug, DebugClang and Release +builds are set to code sign using a code signing certificate named +"lldb_codesign". + +If you have re-installed a new OS, please delete all old lldb_codesign items +from your keychain. There will be a code signing certification and a public +and private key. Reboot after deleting them. You will also need to delete and +build folders that contained old signed items. The darwin kernel will cache +code signing using the executable's file system node, so you will need to +delete the file so the kernel clears its cache. + +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 Create +- Click Continue +- Click Done +- Click on the "My Certificates" +- Double click on your new lldb_codesign certificate +- Turn down the "Trust" disclosure triangle, scroll to the "Code Signing" trust + pulldown menu and select "Always Trust" and authenticate as needed using your + username and password. +- Drag the new "lldb_codesign" code signing certificate (not the public or private + keys of the same name) from the "login" keychain to the "System" keychain in the + Keychains pane on the left hand side of the main Keychain Access window. This will + move this certificate to the "System" keychain. You'll have to authorize a few + more times, set it to be "Always trusted" when asked. +- Remove "~/Desktop/lldb_codesign.cer" file on your desktop if there is one. +- In the Keychain Access GUI, click and drag "lldb_codesign" in the "System" keychain + onto the desktop. The drag will create a "~/Desktop/lldb_codesign.cer" file used in + the next step. +- 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 +rm -f ~/Desktop/lldb_codesign.cer + +- Drag the "lldb_codesign" certificate from the "System" keychain back into the + "login" keychain +- Quit Keychain Access +- Reboot +- Clean by removing all previously creating code signed binaries and rebuild + lldb and you should be able to debug. + +When you build your LLDB for the first time, the Xcode GUI will prompt you for permission +to use the "lldb_codesign" keychain. Be sure to click "Always Allow" on your first +build. From here on out, the "lldb_codesign" will be trusted and you can build from the +command line without having to authorize. Also the first time you debug using a LLDB that +was built with this code signing certificate, you will need to authenticate once. diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in new file mode 100644 index 000000000..725a26f2a --- /dev/null +++ b/docs/doxygen.cfg.in @@ -0,0 +1,1631 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = LLVM + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @abs_top_builddir@/docs/cpp_reference + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = ../.. + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 2 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = NO + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = NO + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @abs_top_srcdir@/include/lldb/API \ + @abs_top_srcdir@/docs/doxygen.intro + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = @abs_top_srcdir@/examples + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = @abs_top_srcdir@/docs/img + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 4 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = llvm:: + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = @abs_top_srcdir@/docs/doxygen.header + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = @abs_top_srcdir@/docs/doxygen.footer + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = @abs_top_srcdir@/../../docs/doxygen.css + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = ../scripts/interface + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = YES + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = NO + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = @DOT@ + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/docs/doxygen.footer b/docs/doxygen.footer new file mode 100644 index 000000000..c14814b4a --- /dev/null +++ b/docs/doxygen.footer @@ -0,0 +1,13 @@ +
+ + +
+ + + + diff --git a/docs/doxygen.header b/docs/doxygen.header new file mode 100644 index 000000000..e6e0331cb --- /dev/null +++ b/docs/doxygen.header @@ -0,0 +1,9 @@ + + + + + +LLVM: $title + + +

LLDB API Documentation

diff --git a/docs/doxygen.intro b/docs/doxygen.intro new file mode 100644 index 000000000..1e5cd2787 --- /dev/null +++ b/docs/doxygen.intro @@ -0,0 +1,19 @@ +/// @mainpage LLDB +/// +/// @section main_intro Introduction +/// Welcome to LLDB. +/// +/// This documentation describes the @b interface that can drive LLDB. +/// There are no instructions here on how to use LLDB, only the APIs +/// that make up the software. For usage instructions, please see +/// the help command. +/// +/// @section main_caveat Caveat +/// This documentation is generated directly from the source code with doxygen. +/// Since LLDB is constantly under active development, what you're about to +/// read is out of date! However, it may still be useful since certain portions +/// of LLDB are very stable. +/// +/// @section main_changelog Change Log +/// - Adapted for LLDB 05/25/2013 by Daniel Malea +/// - Original content written 12/30/2003 by Reid Spencer diff --git a/docs/lldb-for-gdb-users.txt b/docs/lldb-for-gdb-users.txt new file mode 100644 index 000000000..d505d6391 --- /dev/null +++ b/docs/lldb-for-gdb-users.txt @@ -0,0 +1,488 @@ +Here's a short precis of how to run lldb if you are familiar with the +gdb command set: + + +1) LLDB Command Structure: + +First some details on lldb command structure to help orient you... + +Unlike gdb's command set, which is rather free-form, we tried to make +the lldb command syntax fairly structured. The commands are all of the +form + + [-options [option-value]] [argument [argument...]] + +The command line parsing is done before command execution, so it is +uniform across all the commands. The command syntax is very simple, +basically arguments, options and option values are all white-space +separated. If you need to put a backslash or double-quote character +in an argument you back-slash it in the argument. That makes the +command syntax more regular, but it also means you may have to +quote some arguments in lldb that you wouldn't in gdb. + +Options can be placed anywhere on the command line, but if the arguments +begin with a "-" then you have to tell lldb that you're done with options +using the "--" option. So for instance, the "process launch" command takes +the "-s" option to mean "stop the process at the first instruction". It's +arguments are the arguments you are passing to the program. So if you wanted +to pass an argument that contained a "-" you would have to do: + +(lldb) process launch -- -program_arg value + +We also tried to reduce the number of special purpose argument +parsers, which sometimes forces the user to be a little more explicit +about stating their intentions. The first instance you'll note of +this is the breakpoint command. In gdb, to set a breakpoint, you +would just say: + +(gdb) break foo.c:12 + +or + +(gdb) break foo + +if foo is a function. As time went on, the parser that tells foo.c:12 +from foo from foo.c::foo (which means the function foo in the file +foo.c) got more and more complex and bizarre, and especially in C++ +there are times where there's really no way to specify the function +you want to break on. The lldb commands are more verbose but also precise. +So you say: + +(lldb) breakpoint set -f foo.c -l 12 + +to set a file & line breakpoint. To set a breakpoint on a function +by name, you do: + +(lldb) breakpoint set -n foo + +This can allow us to be more expressive, so you can say: + +(lldb) breakpoint set -M foo + +to break on all C++ methods named foo, or: + +(lldb) breakpoint set -S alignLeftEdges: + +to set a breakpoint on all ObjC selectors called alignLeftEdges:. It +also makes it easy to compose specifications, like: + +(lldb) breakpoint set -s foo.dylib -n foo + +for all functions called foo in the shared library foo.dylib. Suggestions +on more interesting primitives of this sort are also very welcome. + +So for instance: + +(lldb) breakpoint set -n "-[SKTGraphicView alignLeftEdges:]" + +Just like gdb, the lldb command interpreter does a shortest unique +string match on command names, so the previous command can also be +typed: + +(lldb) b s -n "-[SKTGraphicView alignLeftEdges:]" + +lldb also supports command completion for source file names, symbol +names, file names, etc. Completion is initiated by a hitting a . +Individual options in a command can have different completers, so for +instance the -f option in "breakpoint" completes to source files, the +-s option to currently loaded shared libraries, etc... We can even do +things like if you specify -s, and are completing on -f, we will only +list source files in the shared library specified by -s... + +The individual commands are pretty extensively documented, using +the "help" command. And there is an "apropos" command that will +search the help for a particular word and dump a summary help string +for each matching command. + +Finally, there is a mechanism to construct aliases for commonly used +commands. So for instance if you get annoyed typing + +(lldb) b s -f foo.c -l 12 + +you can do: + +(lldb) command alias bfl breakpoint set -f %1 -l %2 +(lldb) bfl foo.c 12 + +We have added a few aliases for commonly used commands (e.g. "step", +"next" and "continue") but we haven't tried to be exhaustive because +in our experience it is more convenient to make the basic commands +unique down to a letter or two, and then learn these sequences than +fill the namespace with lots of aliases, and then have to type them +all the way out. + +However, users are free to customize lldb's command set however they +like, and since lldb reads the file ~/.lldbinit at startup, you can +store all your aliases there and they will be generally available to +you. Your aliases are also documented in the help command so you can +remind yourself of what you've set up. + +lldb also has a built-in Python interpreter, which is accessible by +the "script" command. All the functionality of the debugger is +available as classes in the Python interpreter, so the more complex +commands that in gdb you would introduce with the "define" command can +be done by writing Python functions using the lldb-Python library, +then loading the scripts into your running session and accessing them +with the "script" command. + + + +2) A typical session: + + +a) Setting the program to debug: + + +As with gdb, you can start lldb and specify the file you wish to debug +on the command line: + +$ lldb /Projects/Sketch/build/Debug/Sketch.app +Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64). + +or you can specify it after the fact with the "file" command: + +(lldb) file /Projects/Sketch/build/Debug/Sketch.app +Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64). + + +b) Setting breakpoints: + + +We've discussed how to set breakpoints above. You can use "help break set" +to see all the options for breakpoint setting. For instance, we might do: + +(lldb) b s -S alignLeftEdges: +Breakpoint created: 1: name = 'alignLeftEdges:', locations = 1, resolved = 1 + +You can find out about the breakpoints you've set with: + +(lldb) break list +Current breakpoints: +1: name = 'alignLeftEdges:', locations = 1, resolved = 1 + 1.1: where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405, address = 0x0000000100010d5b, resolved, hit count = 0 + +Note that each "logical" breakpoint can have multiple "locations". +The logical breakpoint has an integer id, and it's locations have an +id within their parent breakpoint (the two are joined by a ".", +e.g. 1.1 in the example above.) + +Also the breakpoints remain "live" so that if another shared library +were to be loaded that had another implementation of the +"alignLeftEdges:" selector, the new location would be added to +breakpoint 1 (e.g. a "1.2" breakpoint would be set on the newly loaded +selector). + +The other piece of information in the breakpoint listing is whether the +breakpoint location was "resolved" or not. A location gets resolved when +the file address it corresponds to gets loaded into the program you are +debugging. For instance if you set a breakpoint in a shared library that +then gets unloaded, that breakpoint location will remain, but it will no +longer be "resolved". + +One other thing to note for gdb users is that lldb acts like gdb with: + +(gdb) set breakpoint pending on + +That is, lldb should always make a breakpoint from your specification, even +if it couldn't find any locations that match the specification. You can tell +whether the expression was resolved or not by checking the locations field +in "breakpoint list", and we report the breakpoint as "pending" when you +set it so you can tell you've made a typo more easily, if that was indeed +the reason no locations were found: + +(lldb) b s -f no_such_file.c -l 10000000 +Breakpoint created: 1: file ='no_such_file.c', line = 10000000, locations = 0 (pending) + +You can delete, disable, set conditions and ignore counts either on all the +locations generated by your logical breakpoint, or on particular locations +your specification resolved to. For instance if we wanted to add a command +to print a backtrace when we hit this breakpoint we could do: + +(lldb) b command add -c 1.1 +Enter your debugger command(s). Type 'DONE' to end. +> bt +> DONE + +The "-c" option specifies that the breakpoint command is a set of lldb +command interpreter commands. Use "-s" if you want to implement your +breakpoint command using the Python interface instead. + + +c) Running the program: + +Then you can either launch the process with the command: + +(lldb) process launch + +or its alias: + +(lldb) r + +Or you can attach to a process by name with: + +(lldb) process attach -n Sketch + +The "attach by name" also supports the "-w" option which waits for the +next process of that name to show up, and attaches to that. You can also +attach by PID: + +(lldb) process attach -p 12345 +Process 46915 Attaching +(lldb) Process 46915 Stopped +1 of 3 threads stopped with reasons: +* thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread + +Note that we tell you that "1 of 3 threads stopped with reasons" and +then list those threads. In a multi-threaded environment it is very +common for more than one thread to hit your breakpoint(s) before the +kernel actually returns control to the debugger. In that case, you +will see all the threads that stopped for some interesting reason +listed in the stop message. + + +d) Controlling execution: + + +After launching, we can continue until we hit our breakpoint. The primitive +commands for process control all exist under the "thread" command: + +(lldb) thread continue +Resuming thread 0x2c03 in process 46915 +Resuming process 46915 +(lldb) + +At present you can only operate on one thread at a time, but the +design will ultimately support saying "step over the function in +Thread 1, and step into the function in Thread 2, and continue Thread +3" etc. When we eventually support keeping some threads running while +others are stopped this will be particularly important. For +convenience, however, all the stepping commands have easy aliases. +So "thread continue" is just "c", etc. + +The other program stepping commands are pretty much the same as in gdb. +You've got: + + 1. (lldb) thread step-in + The same as gdb's "step" -- there is also the alias "s" in lldb + + 2. (lldb) thread step-over + The same as gdb's "next" -- there is also the alias "n" in lldb + + 3. (lldb) thread step-out + The same as gdb's "finish" -- there is also the alias "f" in lldb + +And the "by instruction" versions: + +(lldb) thread step-inst +(lldb) thread step-over-inst + +Finally, there's: + +(lldb) thread until 100 + +Which runs the thread in the current frame till it reaches line 100 in +this frame or stops if it leaves the current frame. This is a pretty +close equivalent to gdb's "until" command. + + +One thing here that might be a little disconcerting to gdb users here is that +when you resume process execution, you immediately get a prompt back. That's +because the lldb interpreter remains live when you are running the target. +This allows you to set a breakpoint, etc without having to explicitly interrupt +the program you are debugging. We're still working out all the operations +that it is safe to do while running. But this way of operation will set us +up for "no stop" debugging when we get to implementing that. + +If you want to interrupt a running program do: + +(lldb) process interrupt + +To find out the state of the program, use: + +(lldb) process status +Process 47958 is running. + +This is very convenient, but it does have the down-side that debugging +programs that use stdin is no longer as straightforward. For now, you +have to specify another tty to use as the program stdout & stdin using +the appropriate options to "process launch", or start your program in +another terminal and catch it with "process attach -w". We will come +up with some more convenient way to juggle the terminal back & forth +over time. + + +e) Examining program state: + +Once you've stopped, lldb will choose a current thread, usually the +one that stopped "for a reason", and a current frame in that thread. +Many the commands for inspecting state work on this current +thread/frame. + +To inspect the current state of your process, you can start with the +threads: + +(lldb) thread list +Process 46915 state is Stopped +* thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread + thread #2: tid = 0x2e03, 0x00007fff85cbb08a, where = libSystem.B.dylib`kevent + 10, queue = com.apple.libdispatch-manager + thread #3: tid = 0x2f03, 0x00007fff85cbbeaa, where = libSystem.B.dylib`__workq_kernreturn + 10 + +The * indicates that Thread 1 is the current thread. To get a +backtrace for that thread, do: + +(lldb) thread backtrace +thread #1: tid = 0x2c03, stop reason = breakpoint 1.1, queue = com.apple.main-thread + frame #0: 0x0000000100010d5b, where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405 + frame #1: 0x00007fff8602d152, where = AppKit`-[NSApplication sendAction:to:from:] + 95 + frame #2: 0x00007fff860516be, where = AppKit`-[NSMenuItem _corePerformAction] + 365 + frame #3: 0x00007fff86051428, where = AppKit`-[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:] + 121 + frame #4: 0x00007fff860370c1, where = AppKit`-[NSMenu performKeyEquivalent:] + 272 + frame #5: 0x00007fff86035e69, where = AppKit`-[NSApplication _handleKeyEquivalent:] + 559 + frame #6: 0x00007fff85f06aa1, where = AppKit`-[NSApplication sendEvent:] + 3630 + frame #7: 0x00007fff85e9d922, where = AppKit`-[NSApplication run] + 474 + frame #8: 0x00007fff85e965f8, where = AppKit`NSApplicationMain + 364 + frame #9: 0x0000000100015ae3, where = Sketch`main + 33 at /Projects/Sketch/SKTMain.m:11 + frame #10: 0x0000000100000f20, where = Sketch`start + 52 + +You can also provide a list of threads to backtrace, or the keyword +"all" to see all threads: + +(lldb) thread backtrace all + +Next task is inspecting data: + +The most convenient way to inspect a frame's arguments and local variables is: + +(lldb) frame variable +self = (SKTGraphicView *) 0x0000000100208b40 +_cmd = (struct objc_selector *) 0x000000010001bae1 +sender = (id) 0x00000001001264e0 +selection = (NSArray *) 0x00000001001264e0 +i = (NSUInteger) 0x00000001001264e0 +c = (NSUInteger) 0x00000001001253b0 + +You can also choose particular variables to view: + +(lldb) frame variable self +(SKTGraphicView *) self = 0x0000000100208b40 + +The frame variable command is not a full expression parser but it +does support some common operations like dereferencing: + +(lldb) fr v *self +(SKTGraphicView *) self = 0x0000000100208b40 + (NSView) NSView = { + (NSResponder) NSResponder = { +... + +and structure element references: + +(lldb) frame variable self.isa +(struct objc_class *) self.isa = 0x0000000100023730 + +The frame variable command will also perform "object printing" operations on +variables (currently we only support NSPrintForDebugger) with: + +(lldb) fr v -o self +(SKTGraphicView *) self = 0x0000000100208b40 + + +You can select another frame to view with: + +(lldb) frame select 9 +frame #9: 0x0000000100015ae3, where = Sketch`main + 33 at /Projects/Sketch/SKTMain.m:11 + 8 + 9 + 10 int main(int argc, const char *argv[]) { + 11 -> return NSApplicationMain(argc, argv); + 12 } + 13 + 14 + +Another neat trick that the variable list does is array references, so: + +(lldb) fr v argv[0] +(char const *) argv[0] = 0x00007fff5fbffaf8 "/Projects/Sketch/build/Debug/Sketch.app/Contents/MacOS/Sketch" + +If you need to view more complex data or change program data, you can +use the general "expression" command. It takes an expression and +evaluates it in the scope of the currently selected frame. For instance: + +(lldb) expr self +$0 = (SKTGraphicView *) 0x0000000100135430 +(lldb) expr self = 0x00 +$1 = (SKTGraphicView *) 0x0000000000000000 +(lldb) frame var self +(SKTGraphicView *) self = 0x0000000000000000 + +You can also call functions: + +(lldb) expr (int) printf ("I have a pointer 0x%llx.\n", self) +$2 = (int) 22 +I have a pointer 0x0. + +One thing to note from this example is that lldb commands can be defined to +take "raw" input. "expression" is one of these. So in the expression command, +you don't have to quote your whole expression, nor backslash protect quotes, +etc... + +Finally, the results of the expressions are stored in persistent variables +(of the form $[0-9]+) that you can use in further expressions, like: + +(lldb) expr self = $0 +$4 = (SKTGraphicView *) 0x0000000100135430 + +f) Customization: + +You can use the embedded Python interpreter to add the following 'pwd' and 'cd' commands +for your lldb session: + +(lldb) script import os +(lldb) command alias pwd script print os.getcwd() +(lldb) command regex cd "s/^(.*)$/script os.chdir(os.path.expanduser('%1'))/" + +... + +(lldb) cd /tmp +script os.chdir(os.path.expanduser('/tmp')) +(lldb) pwd +/private/tmp +(lldb) + +Or for a more capable 'cd' command, create ~/utils.py like this: + +import os + +def chdir(debugger, args, result, dict): + """Change the working directory, or cd to ${HOME}.""" + dir = args.strip() + if dir: + os.chdir(args) + else: + os.chdir(os.path.expanduser('~')) + print "Current working directory: %s" % os.getcwd() + +and, have the following in your ~/.lldbinit file: + +script import os, sys +script sys.path.append(os.path.expanduser('~')) +script import utils +command alias pwd script print os.getcwd() +command script add -f utils.chdir cd + +and, then in your lldb session, you can have: + +(lldb) help cd + +Change the working directory, or cd to ${HOME}. +Syntax: cd +(lldb) cd +Current working directory: /Volumes/data/Users/johnny +(lldb) cd /tmp +Current working directory: /private/tmp +(lldb) pwd +/private/tmp +(lldb) + +For more examples of customization, look under the ToT/examples/customization +directory. diff --git a/docs/lldb-gdb-remote.txt b/docs/lldb-gdb-remote.txt new file mode 100644 index 000000000..0000738b5 --- /dev/null +++ b/docs/lldb-gdb-remote.txt @@ -0,0 +1,1915 @@ +LLDB has added new GDB server packets to better support multi-threaded and +remote debugging. Why? Normally you need to start the correct GDB and the +correct GDB server when debugging. If you have mismatch, then things go wrong +very quickly. LLDB makes extensive use of the GDB remote protocol and we +wanted to make sure that the experience was a bit more dynamic where we can +discover information about a remote target with having to know anything up +front. We also ran into performance issues with the existing GDB remote +protocol that can be overcome when using a reliable communications layer. +Some packets improve performance, others allow for remote process launching +(if you have an OS), and others allow us to dynamically figure out what +registers a thread might have. Again with GDB, both sides pre-agree on how the +registers will look (how many, their register number,name and offsets). We +prefer to be able to dynamically determine what kind of architecture, OS and +vendor we are debugging, as well as how things are laid out when it comes to +the thread register contexts. Below are the details on the new packets we have +added above and beyond the standard GDB remote protocol packets. + +//---------------------------------------------------------------------- +// "QStartNoAckMode" +// +// BRIEF +// Try to enable no ACK mode to skip sending ACKs and NACKs. +// +// PRIORITY TO IMPLEMENT +// High. Any GDB remote server that can implement this should if the +// connection is reliable. This improves packet throughput and increases +// the performance of the connection. +//---------------------------------------------------------------------- +Having to send an ACK/NACK after every packet slows things down a bit, so we +have a way to disable ACK packets to minimize the traffic for reliable +communication interfaces (like sockets). Below GDB or LLDB will send this +packet to try and disable ACKs. All lines that start with "send packet: " are +from GDB/LLDB, and all lines that start with "read packet: " are from the GDB +remote server: + +send packet: $QStartNoAckMode#b0 +read packet: + +read packet: $OK#9a +send packet: + + + + +//---------------------------------------------------------------------- +// "A" - launch args packet +// +// BRIEF +// Launch a program using the supplied arguments +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to launch a target after +// making a connection to a GDB server that isn't already connected to +// an inferior process. +//---------------------------------------------------------------------- + +We have added support for the "set program arguments" packet where we can +start a connection to a remote server and then later supply the path to the +executable and the arguments to use when executing: + +GDB remote docs for this: + +set program arguments(reserved) Aarglen,argnum,arg,... + +Where A is followed by the length in bytes of the hex encoded argument, +followed by an argument integer, and followed by the ASCII characters +converted into hex bytes foreach arg + +send packet: $A98,0,2f566f6c756d65732f776f726b2f67636c6179746f6e2f446f63756d656e74732f7372632f6174746163682f612e6f7574#00 +read packet: $OK#00 + +The above packet helps when you have remote debugging abilities where you +could launch a process on a remote host, this isn't needed for bare board +debugging. + +//---------------------------------------------------------------------- +// "QEnvironment:NAME=VALUE" +// +// BRIEF +// Setup the environment up for a new child process that will soon be +// launched using the "A" packet. +// +// NB: key/value pairs are sent as-is so gdb-remote protocol meta characters +// (e.g. '#' or '$') are not acceptable. If any non-printable or +// metacharacters are present in the strings, QEnvironmentHexEncoded +// should be used instead if it is available. If you don't want to +// scan the environment strings before sending, prefer +// the QEnvironmentHexEncoded packet over QEnvironment, if it is +// available. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to launch a target after +// making a connection to a GDB server that isn't already connected to +// an inferior process. +//---------------------------------------------------------------------- + +Both GDB and LLDB support passing down environment variables. Is it ok to +respond with a "$#00" (unimplemented): + +send packet: $QEnvironment:ACK_COLOR_FILENAME=bold yellow#00 +read packet: $OK#00 + +This packet can be sent one or more times _prior_ to sending a "A" packet. + +//---------------------------------------------------------------------- +// "QEnvironmentHexEncoded:HEX-ENCODING(NAME=VALUE)" +// +// BRIEF +// Setup the environment up for a new child process that will soon be +// launched using the "A" packet. +// +// The only difference between this packet and QEnvironment is that the +// environment key-value pair is ascii hex encoded for transmission. +// This allows values with gdb-remote metacharacters like '#' to be sent. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to launch a target after +// making a connection to a GDB server that isn't already connected to +// an inferior process. +//---------------------------------------------------------------------- + +Both GDB and LLDB support passing down environment variables. Is it ok to +respond with a "$#00" (unimplemented): + +send packet: $QEnvironment:41434b5f434f4c4f525f46494c454e414d453d626f6c642379656c6c6f77#00 +read packet: $OK#00 + +This packet can be sent one or more times _prior_ to sending a "A" packet. + +//---------------------------------------------------------------------- +// "QEnableErrorStrings" +// +// BRIEF +// This packet enables reporting of Error strings in remote packet +// replies from the server to client. If the server supports this +// feature, it should send an OK response. The client can expect the +// following error replies if this feature is enabled in the server -> +// +// EXX;AAAAAAAAA +// +// where AAAAAAAAA will be a hex encoded ASCII string. +// XX is hex encoded byte number. +// +// It must be noted that even if the client has enabled reporting +// strings in error replies, it must not expect error strings to all +// error replies. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to provide strings that +// are human readable along with an error code. +//---------------------------------------------------------------------- + +send packet: $QErrorStringInPacketSupported +read packet: $OK#00 + +//---------------------------------------------------------------------- +// "QSetSTDIN:" +// "QSetSTDOUT:" +// "QSetSTDERR:" +// +// BRIEF +// Setup where STDIN, STDOUT, and STDERR go prior to sending an "A" +// packet. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to launch a target after +// making a connection to a GDB server that isn't already connected to +// an inferior process. +//---------------------------------------------------------------------- + +When launching a program through the GDB remote protocol with the "A" packet, +you might also want to specify where stdin/out/err go: + +QSetSTDIN: +QSetSTDOUT: +QSetSTDERR: + +These packets must be sent _prior_ to sending a "A" packet. + +//---------------------------------------------------------------------- +// "QSetWorkingDir:" +// +// BRIEF +// Set the working directory prior to sending an "A" packet. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to launch a target after +// making a connection to a GDB server that isn't already connected to +// an inferior process. +//---------------------------------------------------------------------- + +Or specify the working directory: + +QSetWorkingDir: + +This packet must be sent _prior_ to sending a "A" packet. + +//---------------------------------------------------------------------- +// "QSetDisableASLR:" +// +// BRIEF +// Enable or disable ASLR on the next "A" packet. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed if the remote target wants to launch a target after +// making a connection to a GDB server that isn't already connected to +// an inferior process and if the target supports disabling ASLR +// (Address space layout randomization). +//---------------------------------------------------------------------- + +Or control if ASLR is enabled/disabled: + +send packet: QSetDisableASLR:1 +read packet: OK + +send packet: QSetDisableASLR:0 +read packet: OK + +This packet must be sent _prior_ to sending a "A" packet. + +//---------------------------------------------------------------------- +// QListThreadsInStopReply +// +// BRIEF +// Enable the threads: and thread-pcs: data in the question-mark packet +// ("T packet") responses when the stub reports that a program has +// stopped executing. +// +// PRIORITY TO IMPLEMENT +// Performance. This is a performance benefit to lldb if the thread id's +// and thread pc values are provided to lldb in the T stop packet -- if +// they are not provided to lldb, lldb will likely need to send one to +// two packets per thread to fetch the data at every private stop. +//---------------------------------------------------------------------- + +send packet: QListThreadsInStopReply +read packet: OK + +//---------------------------------------------------------------------- +// jTraceStart: +// +// BRIEF +// Packet for starting trace of type lldb::TraceType. The following +// parameters should be appended to the packet formatted as a JSON +// dictionary, where the schematic for the JSON dictionary in terms of +// the recognized Keys is given below in the table. +// Different tracing types could require different custom parameters. +// Such custom tracing parameters if needed should be collectively +// specified in a JSON dictionary and the dictionary can be appended +// to this packet (as Value corresponding to "params"). Since sending +// JSON data over gdb-remote protocol has certain limitations, binary +// escaping convention should be used. +// +// Following is the list of parameters - +// +// Key Value (Integer) (O)Optional/ +// (except params which should be a (M)Mandatory +// JSON dictionary) +// ========== ==================================================== +// +// type The type of trace to start (see M +// lldb-enumerations for TraceType) +// +// buffersize The size of the buffer to allocate M +// for trace gathering. +// +// threadid The id of the thread to start tracing O +// on. +// +// metabuffersize The size of buffer to hold meta data O +// used for decoding the trace data. +// +// params Any parameters that are specific to O +// certain trace technologies should be +// collectively specified as a JSON +// dictionary +// ========== ==================================================== +// +// Each tracing instance is identified by a trace id which is returned +// as the reply to this packet. In case the tracing failed to begin an +// error code along with a hex encoded ASCII message is returned +// instead. +//---------------------------------------------------------------------- + +send packet: jTraceStart:{"type":,"buffersize":}] +read packet: /E;AAAAAAAAA + +//---------------------------------------------------------------------- +// jTraceStop: +// +// BRIEF +// Stop tracing instance with trace id , of course trace +// needs to be started before. The following parameters should be +// formatted as a JSON dictionary to the packet. Since sending +// JSON data over gdb-remote protocol has certain limitations, binary +// escaping convention should be used. +// +// Following is the list of parameters - +// +// Key Value (Integer) (O)Optional/ +// (M)Mandatory +// ========== ==================================================== +// +// traceid The trace id of the tracing instance M +// +// threadid The id of the thread to stop tracing O +// on. Since could map to +// multiple trace instances (in case it +// maps to the complete process), the +// threadid of a particular thread could +// be appended as "threadid:;" +// to stop tracing on that thread. +// ========== ==================================================== +// +// An OK response is sent in case of success else an error code along +// with a hex encoded ASCII message is returned. +//---------------------------------------------------------------------- + +send packet: jTraceStop:{"traceid":}] +read packet: /E;AAAAAAAAA + +//---------------------------------------------------------------------- +// jTraceBufferRead: +// +// BRIEF +// Packet for reading the trace for tracing instance , i.e the +// id obtained from StartTrace API. The following parameters should be +// formatted as a JSON dictionary to the packet. Since sending +// JSON data over gdb-remote protocol has certain limitations, binary +// escaping convention should be used. +// +// Following is the list of parameters - +// +// Key Value (Integer) (O)Optional/ +// (M)Mandatory +// ========== ==================================================== +// traceid The trace id of the tracing instance M +// +// offset The offset to start reading the data M +// from. +// +// buffersize The size of the data intended to read. M +// +// threadid The id of the thread to retrieve data O +// from. +// ========== ==================================================== +// +// The trace data is sent as raw binary data if the read was successful +// else an error code along with a hex encoded ASCII message is sent. +//---------------------------------------------------------------------- + +send packet: jTraceBufferRead:{"traceid":,"offset":,"buffersize":}] +read packet: /E;AAAAAAAAA + +//---------------------------------------------------------------------- +// jTraceMetaRead: +// +// BRIEF +// Similar Packet as above except it reads meta data. +//---------------------------------------------------------------------- + +/---------------------------------------------------------------------- +// jTraceConfigRead: +// +// BRIEF +// Request the trace configuration for the tracing instance with id +// . +// +// Following is the list of parameters - +// +// Key Value (Integer) (O)Optional/ +// (M)Mandatory +// ========== ==================================================== +// traceid The trace id of the tracing instance M +// +// threadid The id of the thread to obtain trace O +// configuration from. Since +// could map to multiple trace instances +// (in case it maps to the complete +// process), the threadid of a particular +// thread could be appended as +// "threadid:;" to obtain the +// trace configuration of that thread. +// ========== ==================================================== +// +// In the response packet the trace configuration is sent as text, +// formatted as a JSON dictionary. Since sending JSON data over +// gdb-remote protocol has certain limitations, binary escaping +// convention is used. +// In case the trace instance with the was not found, an +// error code along with a hex encoded ASCII message is returned. +//---------------------------------------------------------------------- + +send packet: jTraceConfigRead:{"traceid":} +read packet: {"conf1":,"conf2":,"params":{"paramName":paramValue}]}];/E;AAAAAAAAA + +//---------------------------------------------------------------------- +// "qRegisterInfo" +// +// BRIEF +// Discover register information from the remote GDB server. +// +// PRIORITY TO IMPLEMENT +// High. Any target that can self describe its registers, should do so. +// This means if new registers are ever added to a remote target, they +// will get picked up automatically, and allows registers to change +// depending on the actual CPU type that is used. +// +// NB: As of summer 2015, lldb can get register information from the +// "qXfer:features:read:target.xml" FSF gdb standard register packet +// where the stub provides register definitions in an XML file. +// If qXfer:features:read:target.xml is supported, qRegisterInfo does +// not need to be implemented. +//---------------------------------------------------------------------- + +With LLDB, for register information, remote GDB servers can add +support for the "qRegisterInfoN" packet where "N" is a zero based +base16 register number that must start at zero and increase by one +for each register that is supported. The response is done in typical +GDB remote fashion where a series of "KEY:VALUE;" pairs are returned. +An example for the x86_64 registers is included below: + +send packet: $qRegisterInfo0#00 +read packet: $name:rax;bitsize:64;offset:0;encoding:uint;format:hex;set:General Purpose Registers;gcc:0;dwarf:0;#00 +send packet: $qRegisterInfo1#00 +read packet: $name:rbx;bitsize:64;offset:8;encoding:uint;format:hex;set:General Purpose Registers;gcc:3;dwarf:3;#00 +send packet: $qRegisterInfo2#00 +read packet: $name:rcx;bitsize:64;offset:16;encoding:uint;format:hex;set:General Purpose Registers;gcc:2;dwarf:2;#00 +send packet: $qRegisterInfo3#00 +read packet: $name:rdx;bitsize:64;offset:24;encoding:uint;format:hex;set:General Purpose Registers;gcc:1;dwarf:1;#00 +send packet: $qRegisterInfo4#00 +read packet: $name:rdi;bitsize:64;offset:32;encoding:uint;format:hex;set:General Purpose Registers;gcc:5;dwarf:5;#00 +send packet: $qRegisterInfo5#00 +read packet: $name:rsi;bitsize:64;offset:40;encoding:uint;format:hex;set:General Purpose Registers;gcc:4;dwarf:4;#00 +send packet: $qRegisterInfo6#00 +read packet: $name:rbp;alt-name:fp;bitsize:64;offset:48;encoding:uint;format:hex;set:General Purpose Registers;gcc:6;dwarf:6;generic:fp;#00 +send packet: $qRegisterInfo7#00 +read packet: $name:rsp;alt-name:sp;bitsize:64;offset:56;encoding:uint;format:hex;set:General Purpose Registers;gcc:7;dwarf:7;generic:sp;#00 +send packet: $qRegisterInfo8#00 +read packet: $name:r8;bitsize:64;offset:64;encoding:uint;format:hex;set:General Purpose Registers;gcc:8;dwarf:8;#00 +send packet: $qRegisterInfo9#00 +read packet: $name:r9;bitsize:64;offset:72;encoding:uint;format:hex;set:General Purpose Registers;gcc:9;dwarf:9;#00 +send packet: $qRegisterInfoa#00 +read packet: $name:r10;bitsize:64;offset:80;encoding:uint;format:hex;set:General Purpose Registers;gcc:10;dwarf:10;#00 +send packet: $qRegisterInfob#00 +read packet: $name:r11;bitsize:64;offset:88;encoding:uint;format:hex;set:General Purpose Registers;gcc:11;dwarf:11;#00 +send packet: $qRegisterInfoc#00 +read packet: $name:r12;bitsize:64;offset:96;encoding:uint;format:hex;set:General Purpose Registers;gcc:12;dwarf:12;#00 +send packet: $qRegisterInfod#00 +read packet: $name:r13;bitsize:64;offset:104;encoding:uint;format:hex;set:General Purpose Registers;gcc:13;dwarf:13;#00 +send packet: $qRegisterInfoe#00 +read packet: $name:r14;bitsize:64;offset:112;encoding:uint;format:hex;set:General Purpose Registers;gcc:14;dwarf:14;#00 +send packet: $qRegisterInfof#00 +read packet: $name:r15;bitsize:64;offset:120;encoding:uint;format:hex;set:General Purpose Registers;gcc:15;dwarf:15;#00 +send packet: $qRegisterInfo10#00 +read packet: $name:rip;alt-name:pc;bitsize:64;offset:128;encoding:uint;format:hex;set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;#00 +send packet: $qRegisterInfo11#00 +read packet: $name:rflags;alt-name:flags;bitsize:64;offset:136;encoding:uint;format:hex;set:General Purpose Registers;#00 +send packet: $qRegisterInfo12#00 +read packet: $name:cs;bitsize:64;offset:144;encoding:uint;format:hex;set:General Purpose Registers;#00 +send packet: $qRegisterInfo13#00 +read packet: $name:fs;bitsize:64;offset:152;encoding:uint;format:hex;set:General Purpose Registers;#00 +send packet: $qRegisterInfo14#00 +read packet: $name:gs;bitsize:64;offset:160;encoding:uint;format:hex;set:General Purpose Registers;#00 +send packet: $qRegisterInfo15#00 +read packet: $name:fctrl;bitsize:16;offset:176;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo16#00 +read packet: $name:fstat;bitsize:16;offset:178;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo17#00 +read packet: $name:ftag;bitsize:8;offset:180;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo18#00 +read packet: $name:fop;bitsize:16;offset:182;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo19#00 +read packet: $name:fioff;bitsize:32;offset:184;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo1a#00 +read packet: $name:fiseg;bitsize:16;offset:188;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo1b#00 +read packet: $name:fooff;bitsize:32;offset:192;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo1c#00 +read packet: $name:foseg;bitsize:16;offset:196;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo1d#00 +read packet: $name:mxcsr;bitsize:32;offset:200;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo1e#00 +read packet: $name:mxcsrmask;bitsize:32;offset:204;encoding:uint;format:hex;set:Floating Point Registers;#00 +send packet: $qRegisterInfo1f#00 +read packet: $name:stmm0;bitsize:80;offset:208;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:33;dwarf:33;#00 +send packet: $qRegisterInfo20#00 +read packet: $name:stmm1;bitsize:80;offset:224;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:34;dwarf:34;#00 +send packet: $qRegisterInfo21#00 +read packet: $name:stmm2;bitsize:80;offset:240;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:35;dwarf:35;#00 +send packet: $qRegisterInfo22#00 +read packet: $name:stmm3;bitsize:80;offset:256;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:36;dwarf:36;#00 +send packet: $qRegisterInfo23#00 +read packet: $name:stmm4;bitsize:80;offset:272;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:37;dwarf:37;#00 +send packet: $qRegisterInfo24#00 +read packet: $name:stmm5;bitsize:80;offset:288;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:38;dwarf:38;#00 +send packet: $qRegisterInfo25#00 +read packet: $name:stmm6;bitsize:80;offset:304;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:39;dwarf:39;#00 +send packet: $qRegisterInfo26#00 +read packet: $name:stmm7;bitsize:80;offset:320;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:40;dwarf:40;#00 +send packet: $qRegisterInfo27#00 +read packet: $name:xmm0;bitsize:128;offset:336;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:17;dwarf:17;#00 +send packet: $qRegisterInfo28#00 +read packet: $name:xmm1;bitsize:128;offset:352;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:18;dwarf:18;#00 +send packet: $qRegisterInfo29#00 +read packet: $name:xmm2;bitsize:128;offset:368;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:19;dwarf:19;#00 +send packet: $qRegisterInfo2a#00 +read packet: $name:xmm3;bitsize:128;offset:384;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:20;dwarf:20;#00 +send packet: $qRegisterInfo2b#00 +read packet: $name:xmm4;bitsize:128;offset:400;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:21;dwarf:21;#00 +send packet: $qRegisterInfo2c#00 +read packet: $name:xmm5;bitsize:128;offset:416;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:22;dwarf:22;#00 +send packet: $qRegisterInfo2d#00 +read packet: $name:xmm6;bitsize:128;offset:432;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:23;dwarf:23;#00 +send packet: $qRegisterInfo2e#00 +read packet: $name:xmm7;bitsize:128;offset:448;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:24;dwarf:24;#00 +send packet: $qRegisterInfo2f#00 +read packet: $name:xmm8;bitsize:128;offset:464;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:25;dwarf:25;#00 +send packet: $qRegisterInfo30#00 +read packet: $name:xmm9;bitsize:128;offset:480;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:26;dwarf:26;#00 +send packet: $qRegisterInfo31#00 +read packet: $name:xmm10;bitsize:128;offset:496;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:27;dwarf:27;#00 +send packet: $qRegisterInfo32#00 +read packet: $name:xmm11;bitsize:128;offset:512;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:28;dwarf:28;#00 +send packet: $qRegisterInfo33#00 +read packet: $name:xmm12;bitsize:128;offset:528;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:29;dwarf:29;#00 +send packet: $qRegisterInfo34#00 +read packet: $name:xmm13;bitsize:128;offset:544;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:30;dwarf:30;#00 +send packet: $qRegisterInfo35#00 +read packet: $name:xmm14;bitsize:128;offset:560;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:31;dwarf:31;#00 +send packet: $qRegisterInfo36#00 +read packet: $name:xmm15;bitsize:128;offset:576;encoding:vector;format:vector-uint8;set:Floating Point Registers;gcc:32;dwarf:32;#00 +send packet: $qRegisterInfo37#00 +read packet: $name:trapno;bitsize:32;offset:696;encoding:uint;format:hex;set:Exception State Registers;#00 +send packet: $qRegisterInfo38#00 +read packet: $name:err;bitsize:32;offset:700;encoding:uint;format:hex;set:Exception State Registers;#00 +send packet: $qRegisterInfo39#00 +read packet: $name:faultvaddr;bitsize:64;offset:704;encoding:uint;format:hex;set:Exception State Registers;#00 +send packet: $qRegisterInfo3a#00 +read packet: $E45#00 + +As we see above we keep making subsequent calls to the remote server to +discover all registers by increasing the number appended to qRegisterInfo and +we get a response back that is a series of "key=value;" strings. + +The offset: fields should not leave a gap anywhere in the g/G packet -- the +register values should be appended one after another. For instance, if the +register context for a thread looks like + +struct rctx { + uint32_t gpr1; // offset 0 + uint32_t gpr2; // offset 4 + uint32_t gpr3; // offset 8 + uint64_t fp1; // offset 16 +}; + +You may end up with a 4-byte gap between gpr3 and fp1 on architectures +that align values like this. The correct offset: value for fp1 is 12 - +in the g/G packet fp1 will immediately follow gpr3, even though the +in-memory thread structure has an empty 4 bytes for alignment between +these two registers. + +The keys and values are detailed below: + +Key Value +========== ================================================================ +name The primary register name as a string ("rbp" for example) + +alt-name An alternate name for a register as a string ("fp" for example for + the above "rbp") + +bitsize Size in bits of a register (32, 64, etc). Base 10. + +offset The offset within the "g" and "G" packet of the register data for + this register. This is the byte offset once the data has been + transformed into binary, not the character offset into the g/G + packet. Base 10. + +encoding The encoding type of the register which must be one of: + + uint (unsigned integer) + sint (signed integer) + ieee754 (IEEE 754 float) + vector (vector register) + +format The preferred format for display of this register. The value must + be one of: + + binary + decimal + hex + float + vector-sint8 + vector-uint8 + vector-sint16 + vector-uint16 + vector-sint32 + vector-uint32 + vector-float32 + vector-uint128 + +set The register set name as a string that this register belongs to. + +gcc The GCC compiler registers number for this register (used for + EH frame and other compiler information that is encoded in the + executable files). The supplied number will be decoded like a + string passed to strtoul() with a base of zero, so the number + can be decimal, or hex if it is prefixed with "0x". + + NOTE: If the compiler doesn't have a register number for this + register, this key/value pair should be omitted. + +dwarf The DWARF register number for this register that is used for this + register in the debug information. The supplied number will be decoded + like a string passed to strtoul() with a base of zero, so the number + can be decimal, or hex if it is prefixed with "0x". + + NOTE: If the compiler doesn't have a register number for this + register, this key/value pair should be omitted. + +generic If the register is a generic register that most CPUs have, classify + it correctly so the debugger knows. Valid values are one of: + pc (a program counter register. for example "name=eip;" (i386), + "name=rip;" (x86_64), "name=r15;" (32 bit arm) would + include a "generic=pc;" key value pair) + sp (a stack pointer register. for example "name=esp;" (i386), + "name=rsp;" (x86_64), "name=r13;" (32 bit arm) would + include a "generic=sp;" key value pair) + fp (a frame pointer register. for example "name=ebp;" (i386), + "name=rbp;" (x86_64), "name=r7;" (32 bit arm with macosx + ABI) would include a "generic=fp;" key value pair) + ra (a return address register. for example "name=lr;" (32 bit ARM) + would include a "generic=ra;" key value pair) + fp (a CPU flags register. for example "name=eflags;" (i386), + "name=rflags;" (x86_64), "name=cpsr;" (32 bit ARM) + would include a "generic=flags;" key value pair) + arg1 - arg8 (specified for registers that contain function + arguments when the argument fits into a register) + +container-regs + The value for this key is a comma separated list of raw hex (optional + leading "0x") register numbers. + + This specifies that this register is contained in other concrete + register values. For example "eax" is in the lower 32 bits of the + "rax" register value for x86_64, so "eax" could specify that it is + contained in "rax" by specifying the register number for "rax" (whose + register number is 0x00) + + "container-regs:00;" + + If a register is comprised of one or more registers, like "d0" is ARM + which is a 64 bit register, it might be made up of "s0" and "s1". If + the register number for "s0" is 0x20, and the register number of "s1" + is "0x21", the "container-regs" key/value pair would be: + + "container-regs:20,21;" + + This is handy for defining what GDB used to call "pseudo" registers. + These registers are never requested by LLDB via the register read + or write packets, the container registers will be requested on behalf + of this register. + +invalidate-regs + The value for this key is a comma separated list of raw hex (optional + leading "0x") register numbers. + + This specifies which register values should be invalidated when this + register is modified. For example if modifying "eax" would cause "rax", + "eax", "ax", "ah", and "al" to be modified where rax is 0x0, eax is 0x15, + ax is 0x25, ah is 0x35, and al is 0x39, the "invalidate-regs" key/value + pair would be: + + "invalidate-regs:0,15,25,35,39;" + + If there is a single register that gets invalidated, then omit the comma + and just list a single register: + + "invalidate-regs:0;" + + This is handy when modifying a specific register can cause other + register values to change. For example, when debugging an ARM target, + modifying the CPSR register can cause the r8 - r14 and cpsr value to + change depending on if the mode has changed. + +//---------------------------------------------------------------------- +// "qPlatform_shell" +// +// BRIEF +// Run a command in a shell on the connected remote machine. +// +// PRIORITY TO IMPLEMENT +// High. This command allows LLDB clients to run arbitrary shell +// commands on a remote host. +// +/---------------------------------------------------------------------- + +The request consists of the command to be executed encoded in ASCII characters +converted into hex bytes. + +The response to this packet consists of the letter F followed by the return code, +followed by the signal number (or 0 if no signal was delivered), and escaped bytes +of captured program output. + +Below is an example communication from a client sending an "ls -la" command: + +send packet: $qPlatform_shell:6c73202d6c61,00000002#ec +read packet: $F,00000000,00000000,total 4736 +drwxrwxr-x 16 username groupname 4096 Aug 15 21:36 . +drwxr-xr-x 17 username groupname 4096 Aug 10 16:39 .. +-rw-rw-r-- 1 username groupname 73875 Aug 12 16:46 notes.txt +drwxrwxr-x 5 username groupname 4096 Aug 15 21:36 source.cpp +-rw-r--r-- 1 username groupname 2792 Aug 12 16:46 a.out +-rw-r--r-- 1 username groupname 3190 Aug 12 16:46 Makefile + +//---------------------------------------------------------------------- +// "qPlatform_mkdir" +// +// BRIEF +// Creates a new directory on the connected remote machine. +// +// PRIORITY TO IMPLEMENT +// Low. This command allows LLDB clients to create new directories on +// a remote host. +// +/---------------------------------------------------------------------- + +Request: + qPlatform_mkdir:, + +Reply: + F + mkdir called successfully and returned with the given return code + Exx + An error occurred + +//---------------------------------------------------------------------- +// "qPlatform_chmod" +// +// BRIEF +// Change the permissions of a file on the connected remote machine. +// +// PRIORITY TO IMPLEMENT +// Low. This command allows LLDB clients to change the permissions of +// a file on the remote host. +// +/---------------------------------------------------------------------- + +Request: + qPlatform_chmod:, + +Reply: + F + chmod called successfully and returned with the given return code + Exx + An error occurred + +//---------------------------------------------------------------------- +// "qHostInfo" +// +// BRIEF +// Get information about the host we are remotely connected to. +// +// PRIORITY TO IMPLEMENT +// High. This packet is usually very easy to implement and can help +// LLDB select the correct plug-ins for the job based on the target +// triple information that is supplied. +//---------------------------------------------------------------------- + +LLDB supports a host info call that gets all sorts of details of the system +that is being debugged: + +send packet: $qHostInfo#00 +read packet: $cputype:16777223;cpusubtype:3;ostype:darwin;vendor:apple;endian:little;ptrsize:8;#00 + +Key value pairs are one of: + +cputype: is a number that is the mach-o CPU type that is being debugged (base 10) +cpusubtype: is a number that is the mach-o CPU subtype type that is being debugged (base 10) +triple: a string for the target triple (x86_64-apple-macosx) that can be used to specify arch + vendor + os in one entry +vendor: a string for the vendor (apple), not needed if "triple" is specified +ostype: a string for the OS being debugged (macosx, linux, freebsd, ios, watchos), not needed if "triple" is specified +endian: is one of "little", "big", or "pdp" +ptrsize: an unsigned number that represents how big pointers are in bytes on the debug target +hostname: the hostname of the host that is running the GDB server if available +os_build: a string for the OS build for the remote host as a string value +os_kernel: a string describing the kernel version +os_version: a version string that represents the current OS version (10.8.2) +watchpoint_exceptions_received: one of "before" or "after" to specify if a watchpoint is triggered before or after the pc when it stops +default_packet_timeout: an unsigned number that specifies the default timeout in seconds +distribution_id: optional. For linux, specifies distribution id (e.g. ubuntu, fedora, etc.) +osmajor: optional, specifies the major version number of the OS (e.g. for Mac OS X 10.11.2, it would be 10) +osminor: optional, specifies the minor version number of the OS (e.g. for Mac OS X 10.11.2, it would be 11) +ospatch: optional, specifies the patch level number of the OS (e.g. for Mac OS X 10.11.2, it would be 2) + +//---------------------------------------------------------------------- +// "qGDBServerVersion" +// +// BRIEF +// Get version information about this implementation of the gdb-remote +// protocol. +// +// PRIORITY TO IMPLEMENT +// High. This packet is usually very easy to implement and can help +// LLDB to work around bugs in a server's implementation when they +// are found. +//---------------------------------------------------------------------- + +The goal of this packet is to provide enough information about an +implementation of the gdb-remote-protocol server that lldb can +work around implementation problems that are discovered after the +version has been released/deployed. The name and version number +should be sufficiently unique that lldb can unambiguously identify +the origin of the program (for instance, debugserver from lldb) and +the version/submission number/patch level of the program - whatever +is appropriate for your server implementation. + +The packet follows the key-value pair model, semicolon separated. + +send packet: $qGDBServerVersion#00 +read packet: $name:debugserver;version:310.2;#00 + +Other clients may find other key-value pairs to be useful for identifying +a gdb stub. Patch level, release name, build number may all be keys that +better describe your implementation's version. +Suggested key names: + + name : the name of your remote server - "debugserver" is the lldb standard + implementation + + version : identifies the version number of this server + + patch_level : the patch level of this server + + release_name : the name of this release, if your project uses names + + build_number : if you use a build system with increasing build numbers, + this may be the right key name for your server + + major_version : major version number + minor_version : minor version number + +//---------------------------------------------------------------------- +// "qProcessInfo" +// +// BRIEF +// Get information about the process we are currently debugging. +// +// PRIORITY TO IMPLEMENT +// Medium. On systems which can launch multiple different architecture processes, +// the qHostInfo may not disambiguate sufficiently to know what kind of +// process is being debugged. +// e.g. on a 64-bit x86 Mac system both 32-bit and 64-bit user processes are possible, +// and with Mach-O universal files, the executable file may contain both 32- and +// 64-bit slices so it may be impossible to know until you're attached to a real +// process to know what you're working with. +// +// All numeric fields return base-16 numbers without any "0x" prefix. +//---------------------------------------------------------------------- + +An i386 process: + +send packet: $qProcessInfo#00 +read packet: $pid:42a8;parent-pid:42bf;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:7;cpusubtype:3;ostype:macosx;vendor:apple;endian:little;ptrsize:4;#00 + +An x86_64 process: + +send packet: $qProcessInfo#00 +read packet: $pid:d22c;parent-pid:d34d;real-uid:ecf;real-gid:b;effective-uid:ecf;effective-gid:b;cputype:1000007;cpusubtype:3;ostype:macosx;vendor:apple;endian:little;ptrsize:8;#00 + +Key value pairs include: + +pid: the process id +parent-pid: the process of the parent process (often debugserver will become the parent when attaching) +real-uid: the real user id of the process +real-gid: the real group id of the process +effective-uid: the effective user id of the process +effective-gid: the effective group id of the process +cputype: the Mach-O CPU type of the process (base 16) +cpusubtype: the Mach-O CPU subtype of the process (base 16) +ostype: is a string the represents the OS being debugged (darwin, linux, freebsd) +vendor: is a string that represents the vendor (apple) +endian: is one of "little", "big", or "pdp" +ptrsize: is a number that represents how big pointers are in bytes + + +//---------------------------------------------------------------------- +// "qShlibInfoAddr" +// +// BRIEF +// Get an address where the dynamic linker stores information about +// where shared libraries are loaded. +// +// PRIORITY TO IMPLEMENT +// High if you have a dynamic loader plug-in in LLDB for your target +// triple (see the "qHostInfo" packet) that can use this information. +// Many times address load randomization can make it hard to detect +// where the dynamic loader binary and data structures are located and +// some platforms know, or can find out where this information is. +// +// Low if you have a debug target where all object and symbol files +// contain static load addresses. +//---------------------------------------------------------------------- + +LLDB and GDB both support the "qShlibInfoAddr" packet which is a hint to each +debugger as to where to find the dynamic loader information. For darwin +binaries that run in user land this is the address of the "all_image_infos" +structure in the "/usr/lib/dyld" executable, or the result of a TASK_DYLD_INFO +call. The result is returned as big endian hex bytes that are the address +value: + +send packet: $qShlibInfoAddr#00 +read packet: $7fff5fc40040#00 + + + +//---------------------------------------------------------------------- +// "qThreadStopInfo" +// +// BRIEF +// Get information about why a thread, whose ID is "", is stopped. +// +// PRIORITY TO IMPLEMENT +// High if you need to support multi-threaded or multi-core debugging. +// Many times one thread will hit a breakpoint and while the debugger +// is in the process of suspending the other threads, other threads +// will also hit a breakpoint. This packet allows LLDB to know why all +// threads (live system debug) / cores (JTAG) in your program have +// stopped and allows LLDB to display and control your program +// correctly. +//---------------------------------------------------------------------- + +LLDB tries to use the "qThreadStopInfo" packet which is formatted as +"qThreadStopInfo%x" where %x is the hex thread ID. This requests information +about why a thread is stopped. The response is the same as the stop reply +packets and tells us what happened to the other threads. The standard GDB +remote packets love to think that there is only _one_ reason that _one_ thread +stops at a time. This allows us to see why all threads stopped and allows us +to implement better multi-threaded debugging support. + +//---------------------------------------------------------------------- +// "QThreadSuffixSupported" +// +// BRIEF +// Try to enable thread suffix support for the 'g', 'G', 'p', and 'P' +// packets. +// +// PRIORITY TO IMPLEMENT +// High. Adding a thread suffix allows us to read and write registers +// more efficiently and stops us from having to select a thread with +// one packet and then read registers with a second packet. It also +// makes sure that no errors can occur where the debugger thinks it +// already has a thread selected (see the "Hg" packet from the standard +// GDB remote protocol documentation) yet the remote GDB server actually +// has another thread selected. +//---------------------------------------------------------------------- + +When reading thread registers, you currently need to set the current +thread, then read the registers. This is kind of cumbersome, so we added the +ability to query if the remote GDB server supports adding a "thread:;" +suffix to all packets that request information for a thread. To test if the +remote GDB server supports this feature: + +send packet: $QThreadSuffixSupported#00 +read packet: OK + +If "OK" is returned, then the 'g', 'G', 'p' and 'P' packets can accept a +thread suffix. So to send a 'g' packet (read all register values): + +send packet: $g;thread:;#00 +read packet: .... + +send packet: $G;thread:;#00 +read packet: .... + +send packet: $p1a;thread:;#00 +read packet: .... + +send packet: $P1a=1234abcd;thread:;#00 +read packet: .... + + +otherwise, without this you would need to always send two packets: + +send packet: $Hg#00 +read packet: .... +send packet: $g#00 +read packet: .... + +We also added support for allocating and deallocating memory. We use this to +allocate memory so we can run JITed code. + +//---------------------------------------------------------------------- +// "_M," +// +// BRIEF +// Allocate memory on the remote target with the specified size and +// permissions. +// +// PRIORITY TO IMPLEMENT +// High if you want LLDB to be able to JIT code and run that code. JIT +// code also needs data which is also allocated and tracked. +// +// Low if you don't support running JIT'ed code. +//---------------------------------------------------------------------- + +The allocate memory packet starts with "_M,". It returns a +raw big endian address value, or "" for unimplemented, or "EXX" for an error +code. The packet is formatted as: + +char packet[256]; +int packet_len; +packet_len = ::snprintf ( + packet, + sizeof(packet), + "_M%zx,%s%s%s", + (size_t)size, + permissions & lldb::ePermissionsReadable ? "r" : "", + permissions & lldb::ePermissionsWritable ? "w" : "", + permissions & lldb::ePermissionsExecutable ? "x" : ""); + +You request a size and give the permissions. This packet does NOT need to be +implemented if you don't want to support running JITed code. The return value +is just the address of the newly allocated memory as raw big endian hex bytes. + +//---------------------------------------------------------------------- +// "_m" +// +// BRIEF +// Deallocate memory that was previously allocated using an allocate +// memory pack. +// +// PRIORITY TO IMPLEMENT +// High if you want LLDB to be able to JIT code and run that code. JIT +// code also needs data which is also allocated and tracked. +// +// Low if you don't support running JIT'ed code. +//---------------------------------------------------------------------- + +The deallocate memory packet is "_m" where you pass in the address you +got back from a previous call to the allocate memory packet. It returns "OK" +if the memory was successfully deallocated, or "EXX" for an error, or "" if +not supported. + +//---------------------------------------------------------------------- +// "qMemoryRegionInfo:" +// +// BRIEF +// Get information about the address range that contains "" +// +// PRIORITY TO IMPLEMENT +// Medium. This is nice to have, but it isn't necessary. It helps LLDB +// do stack unwinding when we branch into memory that isn't executable. +// If we can detect that the code we are stopped in isn't executable, +// then we can recover registers for stack frames above the current +// frame. Otherwise we must assume we are in some JIT'ed code (not JIT +// code that LLDB has made) and assume that no registers are available +// in higher stack frames. +//---------------------------------------------------------------------- + +We added a way to get information for a memory region. The packet is: + + qMemoryRegionInfo: + +Where is a big endian hex address. The response is returned in a series +of tuples like the data returned in a stop reply packet. The currently valid +tuples to return are: + + start:; // is a big endian hex address that is + // the start address of the range that contains + + size:; // is a big endian hex byte size of the address + // of the range that contains + + permissions:; // is a string that contains one + // or more of the characters from "rwx" + + name:; // is a hex encoded string that contains the name of + // the memory region mapped at the given address. In case of + // regions backed by a file it have to be the absolute path of + // the file while for anonymous regions it have to be the name + // associated to the region if that is available. + + error:; // where is + // a hex encoded string value that + // contains an error string + +If the address requested is not in a mapped region (e.g. we've jumped through +a NULL pointer and are at 0x0) currently lldb expects to get back the size +of the unmapped region -- that is, the distance to the next valid region. +For instance, with a Mac OS X process which has nothing mapped in the first +4GB of its address space, if we're asking about address 0x2, + + qMemoryRegionInfo:2 + start:2;size:fffffffe; + +The lack of 'permissions:' indicates that none of read/write/execute are valid +for this region. + +//---------------------------------------------------------------------- +// "x" - Binary memory read +// +// Like the 'm' (read) and 'M' (write) packets, this is a partner to the +// 'X' (write binary data) packet, 'x'. +// +// It is called like +// +// xADDRESS,LENGTH +// +// where both ADDRESS and LENGTH are big-endian base 16 values. +// +// To test if this packet is available, send a addr/len of 0: +// +// x0,0 +// +// and you will get an "OK" response. +// +// The reply will be the data requested in 8-bit binary data format. +// The standard quoting is applied to the payload -- characters +// } # $ * +// will all be escaped with '}' (0x7d) character and then XOR'ed with 0x20. +// +// A typical use to read 512 bytes at 0x1000 would look like +// +// x0x1000,0x200 +// +// The "0x" prefixes are optional - like most of the gdb-remote packets, +// omitting them will work fine; these numbers are always base 16. +// +// The length of the payload is not provided. A reliable, 8-bit clean, +// transport layer is assumed. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Detach and stay stopped: +// +// We extended the "D" packet to specify that the monitor should keep the +// target suspended on detach. The normal behavior is to resume execution +// on detach. We will send: +// +// qSupportsDetachAndStayStopped: +// +// to query whether the monitor supports the extended detach, and if it does, +// when we want the monitor to detach but not resume the target, we will +// send: +// +// D1 +// +// In any case, if we want the normal detach behavior we will just send: +// +// D +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// QSaveRegisterState +// QSaveRegisterState;thread:XXXX; +// +// BRIEF +// The QSaveRegisterState packet tells the remote debugserver to save +// all registers and return a non-zero unique integer ID that +// represents these save registers. If thread suffixes are enabled the +// second form of this packet is used, otherwise the first form is +// used. This packet is called prior to executing an expression, so +// the remote GDB server should do anything it needs to in order to +// ensure the registers that are saved are correct. On MacOSX this +// involves calling "thread_abort_safely(mach_port_t thread)" to +// ensure we get the correct registers for a thread in case it is +// currently having code run on its behalf in the kernel. +// +// RESPONSE +// unsigned - The save_id result is a non-zero unsigned integer value +// that can be passed back to the GDB server using a +// QRestoreRegisterState packet to restore the registers +// one time. +// "EXX" - or an error code in the form of EXX where XX is a +// hex error code. +// +// PRIORITY TO IMPLEMENT +// Low, this is mostly a convenience packet to avoid having to send all +// registers via a g packet. It should only be implemented if support +// for the QRestoreRegisterState is added. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// QRestoreRegisterState: +// QRestoreRegisterState:;thread:XXXX; +// +// BRIEF +// The QRestoreRegisterState packet tells the remote debugserver to +// restore all registers using the "save_id" which is an unsigned +// integer that was returned from a previous call to +// QSaveRegisterState. The restoration process can only be done once +// as the data backing the register state will be freed upon the +// completion of the QRestoreRegisterState command. +// +// If thread suffixes are enabled the second form of this packet is +// used, otherwise the first form is used. +// +// RESPONSE +// "OK" - if all registers were successfully restored +// "EXX" - for any errors +// +// PRIORITY TO IMPLEMENT +// Low, this is mostly a convenience packet to avoid having to send all +// registers via a g packet. It should only be implemented if support +// for the QSaveRegisterState is added. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// qFileLoadAddress: +// +// BRIEF +// Get the load address of a memory mapped file. +// The load address is defined as the address of the first memory +// region what contains data mapped from the specified file. +// +// RESPONSE +// - Load address of the file in big endian encoding +// "E01" - the requested file isn't loaded +// "EXX" - for any other errors +// +// PRIORITY TO IMPLEMENT +// Low, required if dynamic linker don't fill in the load address of +// some object file in the rendezvous data structure. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// qModuleInfo:; +// +// BRIEF +// Get information for a module by given module path and architecture. +// +// RESPONSE +// "(uuid|md5):...;triple:...;file_offset:...;file_size...;" +// "EXX" - for any errors +// +// PRIORITY TO IMPLEMENT +// Optional, required if dynamic loader cannot fetch module's information like +// UUID directly from inferior's memory. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// jModulesInfo:[{"file":"...",triple:"..."}, ...] +// +// BRIEF +// Get information for a list of modules by given module path and +// architecture. +// +// RESPONSE +// A JSON array of dictionaries containing the following keys: uuid, +// triple, file_path, file_offset, file_size. The meaning of the fields +// is the same as in the qModuleInfo packet. The server signals the +// failure to retrieve the module info for a file by ommiting the +// corresponding array entry from the response. The server may also +// include entries the client did not ask for, if it has reason to +// the modules will be interesting to the client. +// +// PRIORITY TO IMPLEMENT +// Optional. If not implemented, qModuleInfo packet will be used, which +// may be slower if the target contains a large number of modules and +// the communication link has a non-negligible latency. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// Stop reply packet extensions +// +// BRIEF +// This section describes some of the additional information you can +// specify in stop reply packets that help LLDB to know more detailed +// information about your threads. +// +// DESCRIPTION +// Standard GDB remote stop reply packets are reply packets sent in +// response to a packet that made the program run. They come in the +// following forms: +// +// "SAA" +// "S" means signal and "AA" is a hex signal number that describes why +// the thread or stopped. It doesn't specify which thread, so the "T" +// packet is recommended to use instead of the "S" packet. +// +// "TAAkey1:value1;key2:value2;..." +// "T" means a thread stopped due to a unix signal where "AA" is a hex +// signal number that describes why the program stopped. This is +// followed by a series of key/value pairs: +// - If key is a hex number, it is a register number and value is +// the hex value of the register in debuggee endian byte order. +// - If key == "thread", then the value is the big endian hex +// thread-id of the stopped thread. +// - If key == "core", then value is a hex number of the core on +// which the stop was detected. +// - If key == "watch" or key == "rwatch" or key == "awatch", then +// value is the data address in big endian hex +// - If key == "library", then value is ignore and "qXfer:libraries:read" +// packets should be used to detect any newly loaded shared libraries +// +// "WAA" +// "W" means the process exited and "AA" is the exit status. +// +// "XAA" +// "X" means the process exited and "AA" is signal that caused the program +// to exit. +// +// "O" +// "O" means STDOUT has data that was written to its console and is +// being delivered to the debugger. This packet happens asynchronously +// and the debugger is expected to continue to wait for another stop reply +// packet. +// +// LLDB EXTENSIONS +// +// We have extended the "T" packet to be able to also understand the +// following keys and values: +// +// KEY VALUE DESCRIPTION +// =========== ======== ================================================ +// "metype" unsigned mach exception type (the value of the EXC_XXX enumerations) +// as an unsigned integer. For targets with mach +// kernels only. +// +// "mecount" unsigned mach exception data count as an unsigned integer +// For targets with mach kernels only. +// +// "medata" unsigned There should be "mecount" of these and it is the data +// that goes along with a mach exception (as an unsigned +// integer). For targets with mach kernels only. +// +// "name" string The name of the thread as a plain string. The string +// must not contain an special packet characters or +// contain a ':' or a ';'. Use "hexname" if the thread +// name has special characters. +// +// "hexname" ascii-hex An ASCII hex string that contains the name of the thread +// +// "qaddr" hex Big endian hex value that contains the libdispatch +// queue address for the queue of the thread. +// +// "reason" enum The enumeration must be one of: +// "trace" the program stopped after a single instruction +// was executed on a core. Usually done when single +// stepping past a breakpoint +// "breakpoint" a breakpoint set using a 'z' packet was hit. +// "trap" stopped due to user interruption +// "signal" stopped due to an actual unix signal, not +// just the debugger using a unix signal to keep +// the GDB remote client happy. +// "watchpoint". Should be used in conjunction with +// the "watch"/"rwatch"/"awatch" key value pairs. +// "exception" an exception stop reason. Use with +// the "description" key/value pair to describe the +// exceptional event the user should see as the stop +// reason. +// "description" ascii-hex An ASCII hex string that contains a more descriptive +// reason that the thread stopped. This is only needed +// if none of the key/value pairs are enough to +// describe why something stopped. +// +// "threads" comma-sep-base16 A list of thread ids for all threads (including +// the thread that we're reporting as stopped) that +// are live in the process right now. lldb may +// request that this be included in the T packet via +// the QListThreadsInStopReply packet earlier in +// the debug session. +// +// Example: +// threads:63387,633b2,63424,63462,63486; +// +// "thread-pcs" comma-sep-base16 A list of pc values for all threads that currently +// exist in the process, including the thread that +// this T packet is reporting as stopped. +// This key-value pair will only be emitted when the +// "threads" key is already included in the T packet. +// The pc values correspond to the threads reported +// in the "threads" list. The number of pcs in the +// "thread-pcs" list will be the same as the number of +// threads in the "threads" list. +// lldb may request that this be included in the T +// packet via the QListThreadsInStopReply packet +// earlier in the debug session. +// +// Example: +// thread-pcs:dec14,2cf872b0,2cf8681c,2d02d68c,2cf716a8; +// +// BEST PRACTICES: +// Since register values can be supplied with this packet, it is often useful +// to return the PC, SP, FP, LR (if any), and FLAGS registers so that separate +// packets don't need to be sent to read each of these registers from each +// thread. +// +// If a thread is stopped for no reason (like just because another thread +// stopped, or because when one core stops all cores should stop), use a +// "T" packet with "00" as the signal number and fill in as many key values +// and registers as possible. +// +// LLDB likes to know why a thread stopped since many thread control +// operations like stepping over a source line, actually are implemented +// by running the process multiple times. If a breakpoint is hit while +// trying to step over a source line and LLDB finds out that a breakpoint +// is hit in the "reason", we will know to stop trying to do the step +// over because something happened that should stop us from trying to +// do the step. If we are at a breakpoint and we disable the breakpoint +// at the current PC and do an instruction single step, knowing that +// we stopped due to a "trace" helps us know that we can continue +// running versus stopping due to a "breakpoint" (if we have two +// breakpoint instruction on consecutive instructions). So the more info +// we can get about the reason a thread stops, the better job LLDB can +// do when controlling your process. A typical GDB server behavior is +// to send a SIGTRAP for breakpoints _and_ also when instruction single +// stepping, in this case the debugger doesn't really know why we +// stopped and it can make it hard for the debugger to control your +// program correctly. What if a real SIGTRAP was delivered to a thread +// while we were trying to single step? We wouldn't know the difference +// with a standard GDB remote server and we could do the wrong thing. +// +// PRIORITY TO IMPLEMENT +// High. Having the extra information in your stop reply packets makes +// your debug session more reliable and informative. +//---------------------------------------------------------------------- + + +//---------------------------------------------------------------------- +// PLATFORM EXTENSION - for use as a GDB remote platform +//---------------------------------------------------------------------- +// "qfProcessInfo" +// "qsProcessInfo" +// +// BRIEF +// Get the first process info (qfProcessInfo) or subsequent process +// info (qsProcessInfo) for one or more processes on the remote +// platform. The first call gets the first match and subsequent calls +// to qsProcessInfo gets the subsequent matches. Return an error EXX, +// where XX are two hex digits, when no more matches are available. +// +// PRIORITY TO IMPLEMENT +// Required. The qfProcessInfo packet can be followed by a ':' and +// some key value pairs. The key value pairs in the command are: +// +// KEY VALUE DESCRIPTION +// =========== ======== ================================================ +// "name" ascii-hex An ASCII hex string that contains the name of +// the process that will be matched. +// "name_match" enum One of: "equals", "starts_with", "ends_with", +// "contains" or "regex" +// "pid" integer A string value containing the decimal process ID +// "parent_pid" integer A string value containing the decimal parent +// process ID +// "uid" integer A string value containing the decimal user ID +// "gid" integer A string value containing the decimal group ID +// "euid" integer A string value containing the decimal effective user ID +// "egid" integer A string value containing the decimal effective group ID +// "all_users" bool A boolean value that specifies if processes should +// be listed for all users, not just the user that the +// platform is running as +// "triple" string An ASCII triple string ("x86_64", +// "x86_64-apple-macosx", "armv7-apple-ios") +// +// The response consists of key/value pairs where the key is separated from the +// values with colons and each pair is terminated with a semi colon. For a list +// of the key/value pairs in the response see the "qProcessInfoPID" packet +// documentation. +// +// Sample packet/response: +// send packet: $qfProcessInfo#00 +// read packet: $pid:60001;ppid:59948;uid:7746;gid:11;euid:7746;egid:11;name:6c6c6462;triple:x86_64-apple-macosx;#00 +// send packet: $qsProcessInfo#00 +// read packet: $pid:59992;ppid:192;uid:7746;gid:11;euid:7746;egid:11;name:6d64776f726b6572;triple:x86_64-apple-macosx;#00 +// send packet: $qsProcessInfo#00 +// read packet: $E04#00 +//---------------------------------------------------------------------- + + +//---------------------------------------------------------------------- +// PLATFORM EXTENSION - for use as a GDB remote platform +//---------------------------------------------------------------------- +// "qLaunchGDBServer" +// +// BRIEF +// Have the remote platform launch a GDB server. +// +// PRIORITY TO IMPLEMENT +// Required. The qLaunchGDBServer packet must be followed by a ':' and +// some key value pairs. The key value pairs in the command are: +// +// KEY VALUE DESCRIPTION +// =========== ======== ================================================ +// "port" integer A string value containing the decimal port ID or +// zero if the port should be bound and returned +// +// "host" integer The host that connections should be limited to +// when the GDB server is connected to. +// +// The response consists of key/value pairs where the key is separated from the +// values with colons and each pair is terminated with a semi colon. +// +// Sample packet/response: +// send packet: $qLaunchGDBServer:port:0;host:lldb.apple.com;#00 +// read packet: $pid:60025;port:50776;#00 +// +// The "pid" key/value pair is only specified if the remote platform launched +// a separate process for the GDB remote server and can be omitted if no +// process was separately launched. +// +// The "port" key/value pair in the response lets clients know what port number +// to attach to in case zero was specified as the "port" in the sent command. +//---------------------------------------------------------------------- + + +//---------------------------------------------------------------------- +// PLATFORM EXTENSION - for use as a GDB remote platform +//---------------------------------------------------------------------- +// "qProcessInfoPID:PID" +// +// BRIEF +// Have the remote platform get detailed information on a process by +// ID. PID is specified as a decimal integer. +// +// PRIORITY TO IMPLEMENT +// Optional. +// +// The response consists of key/value pairs where the key is separated from the +// values with colons and each pair is terminated with a semi colon. +// +// The key value pairs in the response are: +// +// KEY VALUE DESCRIPTION +// =========== ======== ================================================ +// "pid" integer Process ID as a decimal integer string +// "ppid" integer Parent process ID as a decimal integer string +// "uid" integer A string value containing the decimal user ID +// "gid" integer A string value containing the decimal group ID +// "euid" integer A string value containing the decimal effective user ID +// "egid" integer A string value containing the decimal effective group ID +// "name" ascii-hex An ASCII hex string that contains the name of the process +// "triple" string A target triple ("x86_64-apple-macosx", "armv7-apple-ios") +// +// Sample packet/response: +// send packet: $qProcessInfoPID:60050#00 +// read packet: $pid:60050;ppid:59948;uid:7746;gid:11;euid:7746;egid:11;name:6c6c6462;triple:x86_64-apple-macosx;#00 +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "vAttachName" +// +// BRIEF +// Same as vAttach, except instead of a "pid" you send a process name. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed for "process attach -n". If the packet isn't supported +// then "process attach -n" will fail gracefully. So you need only to support +// it if attaching to a process by name makes sense for your environment. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "vAttachWait" +// +// BRIEF +// Same as vAttachName, except that the stub should wait for the next instance +// of a process by that name to be launched and attach to that. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed to support "process attach -w -n" which will fail +// gracefully if the packet is not supported. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "qAttachOrWaitSupported" +// +// BRIEF +// This is a binary "is it supported" query. Return OK if you support +// vAttachOrWait +// +// PRIORITY TO IMPLEMENT +// Low. This is required if you support vAttachOrWait, otherwise no support +// is needed since the standard "I don't recognize this packet" response +// will do the right thing. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "vAttachOrWait" +// +// BRIEF +// Same as vAttachWait, except that the stub will attach to a process +// by name if it exists, and if it does not, it will wait for a process +// of that name to appear and attach to it. +// +// PRIORITY TO IMPLEMENT +// Low. Only needed to implement "process attach -w -i false -n". If +// you don't implement it but do implement -n AND lldb can somehow get +// a process list from your device, it will fall back on scanning the +// process list, and sending vAttach or vAttachWait depending on +// whether the requested process exists already. This is racy, +// however, so if you want to support this behavior it is better to +// support this packet. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "jThreadExtendedInfo" +// +// BRIEF +// This packet, which takes its arguments as JSON and sends its reply as +// JSON, allows the gdb remote stub to provide additional information +// about a given thread. +// +// PRIORITY TO IMPLEMENT +// Low. This packet is only needed if the gdb remote stub wants to +// provide interesting additional information about a thread for the +// user. +// +// This packet takes its arguments in JSON form ( http://www.json.org ). +// At a minimum, a thread must be specified, for example: +// +// jThreadExtendedInfo:{"thread":612910} +// +// Because this is a JSON string, the thread number is provided in base10. +// Additional key-value pairs may be provided by lldb to the gdb remote +// stub. For instance, on some versions of Mac OS X, lldb can read offset +// information out of the system libraries. Using those offsets, debugserver +// is able to find the Thread Specific Address (TSD) for a thread and include +// that in the return information. So lldb will send these additional fields +// like so: +// +// jThreadExtendedInfo:{"plo_pthread_tsd_base_address_offset":0,"plo_pthread_tsd_base_offset":224,"plo_pthread_tsd_entry_size":8,"thread":612910} +// +// There are no requirements for what is included in the response. A simple +// reply on a Mac OS X Yosemite / iOS 8 may include the pthread_t value, the +// Thread Specific Data (TSD) address, the dispatch_queue_t value if the thread +// is associated with a GCD queue, and the requested Quality of Service (QoS) +// information about that thread. For instance, a reply may look like: +// +// {"tsd_address":4371349728,"requested_qos":{"enum_value":33,"constant_name":"QOS_CLASS_USER_INTERACTIVE","printable_name":"User Interactive"},"pthread_t":4371349504,"dispatch_queue_t":140735087127872} +// +// tsd_address, pthread_t, and dispatch_queue_t are all simple key-value pairs. +// The JSON standard requires that numbers be expressed in base 10 - so all of +// these are. requested_qos is a dictionary with three key-value pairs in it - +// so the UI layer may choose the form most appropriate for displaying to the user. +// +// Sending JSON over gdb-remote protocol introduces some problems. We may be +// sending strings with arbitrary contents in them, including the '#', '$', and '*' +// characters that have special meaning in gdb-remote protocol and cannot occur +// in the middle of the string. The standard solution for this would be to require +// ascii-hex encoding of all strings, or ascii-hex encode the entire JSON payload. +// +// Instead, the binary escaping convention is used for JSON data. This convention +// (e.g. used for the X packet) says that if '#', '$', '*', or '}' are to occur in +// the payload, the character '}' (0x7d) is emitted, then the metacharacter is emitted +// xor'ed by 0x20. The '}' character occurs in every JSON payload at least once, and +// '}' ^ 0x20 happens to be ']' so the raw packet characters for a request will look +// like +// +// jThreadExtendedInfo:{"thread":612910}] +// +// on the wire. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "QEnableCompression" +// +// BRIEF +// This packet enables compression of the packets that the debug stub sends to lldb. +// If the debug stub can support compression, it indictes this in the reply of the +// "qSupported" packet. e.g. +// LLDB SENDS: qSupported:xmlRegisters=i386,arm,mips +// STUB REPLIES: qXfer:features:read+;SupportedCompressions=lzfse,zlib-deflate,lz4,lzma;DefaultCompressionMinSize=384 +// +// If lldb knows how to use any of these compression algorithms, it can ask that this +// compression mode be enabled. It may optionally change the minimum packet size +// where compression is used. Typically small packets do not benefit from compression, +// as well as compression headers -- compression is most beneficial with larger packets. +// +// QEnableCompression:type:zlib-deflate; +// or +// QEnableCompression:type:zlib-deflate;minsize:512; +// +// The debug stub should reply with an uncompressed "OK" packet to indicate that the +// request was accepted. All further packets the stub sends will use this compression. +// +// Packets are compressed as the last step before they are sent from the stub, and +// decompressed as the first step after they are received. The packet format in compressed +// mode becomes one of two: +// +// $N#00 +// +// $C:#00 +// +// Where "#00" is the actual checksum value if noack mode is not enabled. The checksum +// value is for the "N" or +// "C:" bytes in the packet. +// +// The size of the uncompressed payload in base10 is provided because it will simplify +// decompression if the final buffer size needed is known ahead of time. +// +// Compression on low-latency connections is unlikely to be an improvement. Particularly +// when the debug stub and lldb are running on the same host. It should only be used +// for slow connections, and likely only for larger packets. +// +// Example compression algorithsm that may be used include +// +// zlib-deflate +// The raw DEFLATE format as described in IETF RFC 1951. With the ZLIB library, you +// can compress to this format with an initialization like +// deflateInit2 (&stream, 5, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) +// and you can decompress with an initialization like +// inflateInit2 (&stream, -15) +// +// lz4 +// https://en.wikipedia.org/wiki/LZ4_(compression_algorithm) +// https://github.com/Cyan4973/lz4 +// The libcompression APIs on darwin systems call this COMPRESSION_LZ4_RAW. +// +// lzfse +// An Apple proprietary compression algorithm implemented in libcompression. +// +// lzma +// libcompression implements "LZMA level 6", the default compression for the +// open source LZMA implementation. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "jGetLoadedDynamicLibrariesInfos" +// +// BRIEF +// This packet asks the remote debug stub to send the details about libraries +// being added/removed from the process as a performance optimization. +// +// There are three ways this packet can be used. All three return a dictionary of +// binary images formatted the same way. +// +// On MacOS X 10.11, iOS 9, tvOS 9, watchOS 2 and earlier, the packet is used like +// jGetLoadedDynamicLibrariesInfos:{"image_count":1,"image_list_address":140734800075128} +// where the image_list_address is an array of {void* load_addr, void* mod_date, void* pathname} +// in the inferior process memory (and image_count is the number of elements in this array). +// lldb is using information from the dyld_all_image_infos structure to make these requests to +// debugserver. This use is not supported on macOS 10.12, iOS 10, tvOS 10, watchOS 3 or newer. +// +// On macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer, there are two calls. One requests information +// on all shared libraries: +// jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true} +// And the second requests information about a list of shared libraries, given their load addresses: +// jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[8382824135,3258302053,830202858503]} +// +// The second call is both a performance optimization (instead of having lldb read the mach-o header/load commands +// out of memory with generic read packets) but also adds additional information in the form of the +// filename of the shared libraries (which is not available in the mach-o header/load commands.) +// +// An example using the Mac OS X 10.11 style call: +// +// LLDB SENDS: jGetLoadedDynamicLibrariesInfos:{"image_count":1,"image_list_address":140734800075128} +// STUB REPLIES: ${"images":[{"load_address":4294967296,"mod_date":0,"pathname":"/tmp/a.out","uuid":"02CF262C-ED6F-3965-9E14-63538B465CFF","mach_header":{"magic":4277009103,"cputype":16777223,"cpusubtype":18446744071562067971,"filetype":2},"segments":{"name":"__PAGEZERO","vmaddr":0,"vmsize":4294967296,"fileoff":0,"filesize":0,"maxprot":0},{"name":"__TEXT","vmaddr":4294967296,"vmsize":4096,"fileoff":0,"filesize":4096,"maxprot":7},{"name":"__LINKEDIT","vmaddr":4294971392,"vmsize":4096,"fileoff":4096,"filesize":152,"maxprot":7}}]}#00 +// +// Or pretty-printed, +// +// STUB REPLIES: ${"images": +// [ +// {"load_address":4294967296, +// "mod_date":0, +// "pathname":"/tmp/a.out", +// "uuid":"02CF262C-ED6F-3965-9E14-63538B465CFF", +// "mach_header": +// {"magic":4277009103, +// "cputype":16777223, +// "cpusubtype":18446744071562067971, +// "filetype":2 +// }, +// "segments": +// [ +// {"name":"__PAGEZERO", +// "vmaddr":0, +// "vmsize":4294967296, +// "fileoff":0, +// "filesize":0, +// "maxprot":0 +// }, +// {"name":"__TEXT", +// "vmaddr":4294967296, +// "vmsize":4096, +// "fileoff":0, +// "filesize":4096, +// "maxprot":7 +// }, +// {"name":"__LINKEDIT", +// "vmaddr":4294971392, +// "vmsize":4096, +// "fileoff":4096, +// "filesize":152, +// "maxprot":7 +// } +// ] +// } +// ] +// } +// +// +// This is similar to the qXfer:libraries:read packet, and it could +// be argued that it should be merged into that packet. A separate +// packet was created primarily because lldb needs to specify the +// number of images to be read and the address from which the initial +// information is read. Also the XML DTD would need to be extended +// quite a bit to provide all the information that the DynamicLoaderMacOSX +// would need to work correctly on this platform. +// +// PRIORITY TO IMPLEMENT +// On Mac OS X 10.11, iOS 9, tvOS 9, watchOS 2 and older: Low. If this packet is absent, +// lldb will read the Mach-O headers/load commands out of memory. +// On macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer: High. If this packet is absent, +// lldb will not know anything about shared libraries in the inferior, or where the main +// executable loaded. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "jThreadsInfo" +// +// BRIEF +// Ask for the server for thread stop information of all threads. +// +// PRIORITY TO IMPLEMENT +// Low. This is a performance optimization, which speeds up debugging by avoiding +// multiple round-trips for retrieving thread information. The information from this +// packet can be retrieved using a combination of qThreadStopInfo and m packets. +//---------------------------------------------------------------------- + +The data in this packet is very similar to the stop reply packets, but is packaged in +JSON and uses JSON arrays where applicable. The JSON output looks like: + [ + { "tid":1580681, + "metype":6, + "medata":[2,0], + "reason":"exception", + "qaddr":140735118423168, + "registers": { + "0":"8000000000000000", + "1":"0000000000000000", + "2":"20fabf5fff7f0000", + "3":"e8f8bf5fff7f0000", + "4":"0100000000000000", + "5":"d8f8bf5fff7f0000", + "6":"b0f8bf5fff7f0000", + "7":"20f4bf5fff7f0000", + "8":"8000000000000000", + "9":"61a8db78a61500db", + "10":"3200000000000000", + "11":"4602000000000000", + "12":"0000000000000000", + "13":"0000000000000000", + "14":"0000000000000000", + "15":"0000000000000000", + "16":"960b000001000000", + "17":"0202000000000000", + "18":"2b00000000000000", + "19":"0000000000000000", + "20":"0000000000000000" + }, + "memory":[ + {"address":140734799804592,"bytes":"c8f8bf5fff7f0000c9a59e8cff7f0000"}, + {"address":140734799804616,"bytes":"00000000000000000100000000000000"} + ] + } + ] + +It contains an array of dictionaries with all of the key value pairs that are +normally in the stop reply packet, including the expedited registers. The registers are +passed as hex-encoded JSON string in debuggee-endian byte order. Note that the register +numbers are decimal numbers, unlike the stop-reply packet, where they are written in +hex. The packet also contains expedited memory in the "memory" key. This allows the +server to expedite memory that the client is likely to use (e.g., areas around the +stack pointer, which are needed for computing backtraces) and it reduces the packet +count. + +On MacOSX with debugserver, we expedite the frame pointer backchain for a thread +(up to 256 entries) by reading 2 pointers worth of bytes at the frame pointer (for +the previous FP and PC), and follow the backchain. Most backtraces on MacOSX and +iOS now don't require us to read any memory! + +//---------------------------------------------------------------------- +// "jGetSharedCacheInfo" +// +// BRIEF +// This packet asks the remote debug stub to send the details about the inferior's +// shared cache. The shared cache is a collection of common libraries/frameworks that +// are mapped into every process at the same address on Darwin systems, and can be +// identified by a load address and UUID. +// +// +// LLDB SENDS: jGetSharedCacheInfo:{} +// STUB REPLIES: ${"shared_cache_base_address":140735683125248,"shared_cache_uuid":"DDB8D70C-C9A2-3561-B2C8-BE48A4F33F96","no_shared_cache":false,"shared_cache_private_cache":false]}#00 +// +// PRIORITY TO IMPLEMENT +// Low. When both lldb and the inferior process are running on the same computer, and lldb +// and the inferior process have the same shared cache, lldb may (as an optimization) read +// the shared cache out of its own memory instead of using gdb-remote read packets to read +// them from the inferior process. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// "qQueryGDBServer" +// +// BRIEF +// Ask the platform for the list of gdbservers we have to connect +// +// PRIORITY TO IMPLEMENT +// Low. The packet is required to support connecting to gdbserver started +// by the platform instance automatically. +//---------------------------------------------------------------------- + +If the remote platform automatically started one or more gdbserver instance (without +lldb asking it) then it have to return the list of port number or socket name for +each of them what can be used by lldb to connect to those instances. + +The data in this packet is a JSON array of JSON objects with the following keys: +"port": (optional) +"socket_name": (optional) + +Example packet: +[ + { "port": 1234 }, + { "port": 5432 }, + { "socket_name": "foo" } +] diff --git a/docs/lldb.1 b/docs/lldb.1 new file mode 100644 index 000000000..a28cabe7a --- /dev/null +++ b/docs/lldb.1 @@ -0,0 +1,154 @@ +.Dd December 16, 2015 \" DATE +.Dt LLDB 1 \" Program name and manual section number +.Os +.Sh NAME \" Section Header - required - do not modify +.Nm lldb +.Nd The debugger +.Sh SYNOPSIS \" Section Header - required - do not modify +.Nm lldb +.Op Fl hvdexw +.Op Fl a Ar arch +.Op Fl c Ar core-file +.Op Fl l Ar script-language +.Op Fl s Ar lldb-commands +.Op Fl n Ar process-name +.Op Fl p Ar pid +.Ar [[--] ...] +.Sh DESCRIPTION \" Section Header - required - do not modify +.Nm +is the command line interface for the LLDB debugger library. +.Nm +can debug C, C++, Objective-C, and Objective-C++ programs. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl h, -help +Prints out the usage information for the +.Nm +debugger. +The +.Fl -help +text may be more up-to-date and +authoritative than the command line options described in this man +page. +.It Fl v, -version +Prints out the version number of the +.Nm +debugger. +.It Fl a, -arch Ar arch +Specifies which architecture +.Nm +will use when launching the specified program (assuming the provided +executable is built for multiple architectures.) +.It Fl f, -file Ar filename +Specifies the executable file that +.Nm +will be launching / attaching to. +.It Fl n, -attach-name Ar process-name +Specifies the name of a currently-running process to attach to. +(or the name of a process to wait for if +.Fl w +is used.) +.It Fl w, -wait-for +When used in concert with +.Fl n Ar process-name , +indicates that +.Nm +should wait for a new process of that name to be started -- and attach +to it as early in the process-launch as possible. +.It Fl p, -attach-pid Ar pid +Specifies a currently running process that +.Nm +should attach to. +.It Fl c, -core Ar core-file +Specifies the core file to examine. +.It Fl l, -script-language Ar 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. +.It Fl d, -debug +Tells the debugger to print out extra information for debugging itself. +.It Fl s, -source Ar filename +Tells +.Nm +to read in and execute the file +.Qq Ar filename , +which should contain +.Nm +commands. +.It Fl e, -editor +Instructs +.Nm +to open source files using the host's "external editor" mechanism. +.It Fl x, -no-lldbinit +Do not automatically parse any '.lldbinit' files. +.Pp +(If you do not provide -f then the first argument will be the file to +be debugged +so 'lldb -- [ []]' also works. +Remember to end the options with "--" if any of your arguments have +a "-" in them.) +.El +.Sh USING LLDB +In +.Nm +there is a +.Cm help +command which can be used to find descriptions and examples of all +.Nm +commands. +To get help on +.Qq Cm breakpoint set +you would type +.Qq Cm help breakpoint set . +.Pp +There is also an +.Cm apropos +command which will search the help text of all commands +for a given term -- this is useful for locating a command by topic. +For instance, +.Qq Cm apropos breakpoint +will list any command that has the word +.Qq Cm breakpoint +in its help text. +.Sh FILES +.Nm +will read settings/aliases/commands from three files at startup, if they exist. +.Pp +First, it will read a +.Pa ~/.lldbinit-debugger +command file. +If you are using the +.Nm +command line interface, this is +.Pa ~/.lldbinit-lldb . +If you are using +.Nm +inside a GUI debugger like +.Nm Xcode +this will be +.Pa ~/.lldbinit-Xcode . +This is a useful place to put settings that you want to apply only when a given +.Nm +command interpreter is used. +.Pp +Second, +.Pa ~/.lldbinit +is read. +.Pp +Third, an +.Pa .lldbinit +file in the current working directory (where +.Nm +is started) will be read. +.Sh SEE ALSO +The LLDB project page http://lldb.llvm.org/ has many different resources for +.Nm +users -- the gdb/lldb command equivalence page http://lldb.llvm.org/lldb-gdb.html can +be especially helpful for users coming from gdb. +.Sh BUGS +To report bugs, please visit http://llvm.org/bugs/ +.Sh AUTHOR +Maintained by the LLDB Team, http://lldb.llvm.org/ diff --git a/docs/structured_data/DarwinLog.md b/docs/structured_data/DarwinLog.md new file mode 100644 index 000000000..c9905829e --- /dev/null +++ b/docs/structured_data/DarwinLog.md @@ -0,0 +1,160 @@ +# Change Notes + +## Summary + +This document describes the DarwinLog logging feature. + +## StructuredDataDarwinLog feature + +The DarwinLog feature supports logging `os_log`*() and `NSLog`() messages +to the command-line lldb console, as well as making those messages +available to LLDB clients via the event system. Starting with fall +2016 OSes, Apple platforms introduce a new fire-hose, stream-style +logging system where the bulk of the log processing happens on the log +consumer side. This reduces logging impact on the system when there +are no consumers, making it cheaper to include logging at all times. +However, it also increases the work needed on the consumer end when +log messages are desired. + +The debugserver binary has been modified to support collection of +`os_log`*()/`NSLog`() messages, selection of which messages appear in the +stream, and fine-grained filtering of what gets passed on to the LLDB +client. DarwinLog also tracks the activity chain (i.e. `os_activity`() +hierarchy) in effect at the time the log messages were issued. The +user is able to configure a number of aspects related to the +formatting of the log message header fields. + +The DarwinLog support is written in a way which should support the +lldb client side on non-Apple clients talking to an Apple device or +macOS system; hence, the plugin support is built into all LLDB +clients, not just those built on an Apple platform. + +StructuredDataDarwinLog implements the 'DarwinLog' feature type, and +the plugin name for it shows up as `darwin-log`. + +The user interface to the darwin-log support is via the following: + +* `plugin structured-data darwin-log enable` command + + This is the main entry point for enabling the command. It can be + set before launching a process or while the process is running. + If the user wants to squelch seeing info-level or debug-level + messages, which is the default behavior, then the enable command + must be made prior to launching the process; otherwise, the + info-level and debug-level messages will always show up. Also, + there is a similar "echo os_log()/NSLog() messages to target + process stderr" mechanism which is properly disabled when enabling + the DarwinLog support prior to launch. This cannot be squelched + if enabling DarwinLog after launch. + + See the help for this command. There are a number of options + to shrink or expand the number of messages that are processed + on the remote side and sent over to the client, and other + options to control the formatting of messages displayed. + + This command is sticky. Once enabled, it will stay enabled for + future process launches. + +* `plugin structured-data darwin-log disable` command + + Executing this command disables os_log() capture in the currently + running process and signals LLDB to stop attempting to launch + new processes with DarwinLog support enabled. + +* `settings set + plugin.structured-data.darwin-log.enable-on-startup true` + + and + + `settings set + plugin.structured-data.darwin-log.auto-enable-options -- `{options} + + When `enable-on-startup` is set to `true`, then LLDB will automatically + enable DarwinLog on startup of relevant processes. It will use the + content provided in the auto-enable-options settings as the + options to pass to the enable command. + + Note the `--` required after auto-enable-command. That is necessary + for raw commands like settings set. The `--` will not become part + of the options for the enable command. + +### Message flow and related performance considerations + +`os_log`()-style collection is not free. The more data that must be +processed, the slower it will be. There are several knobs available +to the developer to limit how much data goes through the pipe, and how +much data ultimately goes over the wire to the LLDB client. The +user's goal should be to ensure he or she only collects as many log +messages are needed, but no more. + +The flow of data looks like the following: + +1. Data comes into debugserver from the low-level OS facility that + receives log messages. The data that comes through this pipe can + be limited or expanded by the `--debug`, `--info` and + `--all-processes` options of the `plugin structured-data darwin-log + enable` command options. Exclude as many categories as possible + here (also the default). The knobs here are very coarse - for + example, whether to include `os_log_info()`-level or + `os_log_debug()`-level info, or to include callstacks in the log + message event data. + +2. The debugserver process filters the messages that arrive through a + message log filter that may be fully customized by the user. It + works similar to a rules-based packet filter: a set of rules are + matched against the log message, each rule tried in sequential + order. The first rule that matches then either accepts or rejects + the message. If the log message does not match any rule, then the + message gets the no-match (i.e. fall-through) action. The no-match + action defaults to accepting but may be set to reject. + + Filters can be added via the enable command's '`--filter` + {filter-spec}' option. Filters are added in order, and multiple + `--filter` entries can be provided to the enable command. + + Filters take the following form: +``` + {action} {attribute} {op} + + {action} := + accept | + reject + + {attribute} := + category | // The log message category + subsystem | // The log message subsystem + activity | // The child-most activity in force + // at the time the message was logged. + activity-chain | // The complete activity chain, specified + // as {parent-activity}:{child-activity}: + // {grandchild-activity} + message | // The fully expanded message contents. + // Note this one is expensive because it + // requires expanding the message. Avoid + // this if possible, or add it further + // down the filter chain. + + {op} := + match {exact-match-text} | + regex {search-regex} // uses C++ std::regex + // ECMAScript variant. +``` + e.g. + `--filter "accept subsystem match com.example.mycompany.myproduct"` + `--filter "accept subsystem regex com.example.+"` + `--filter "reject category regex spammy-system-[[:digit:]]+"` + +3. Messages that are accepted by the log message filter get sent to + the lldb client, where they are mapped to the + StructuredDataDarwinLog plugin. By default, command-line lldb will + issue a Process-level event containing the log message content, and + will request the plugin to print the message if the plugin is + enabled to do so. + +### Log message display + +Several settings control aspects of displaying log messages in +command-line LLDB. See the `enable` command's help for a description +of these. + + diff --git a/docs/structured_data/StructuredDataPlugins.md b/docs/structured_data/StructuredDataPlugins.md new file mode 100644 index 000000000..2a536c787 --- /dev/null +++ b/docs/structured_data/StructuredDataPlugins.md @@ -0,0 +1,136 @@ +# Change Notes + +## Overview + +This document describes an infrastructural feature called Structured +Data plugins. See the `DarwinLog.md` doc for a description of one +such plugin that makes use of this feature. + +## StructuredDataPlugin + +StructuredDataPlugin instances have the following characteristics: + +* Each plugin instance is bound to a single Process instance. + +* Each StructuredData feature has a type name that identifies the + feature. For instance, the type name for the DarwinLog feature is + "DarwinLog". This feature type name is used in various places. + +* The process monitor reports the list of supported StructuredData + features advertised by the process monitor. Process goes through the + list of supported feature type names, and asks each known + StructuredDataPlugin if it can handle the feature. The first plugin + that supports the feature is mapped to that Process instance for + that feature. Plugins are only mapped when the process monitor + advertises that a feature is supported. + +* The feature may send asynchronous messages in StructuredData format + to the Process instance. Process instances route the asynchronous + structured data messages to the plugin mapped to that feature type, + if one exists. + +* Plugins can request that the Process instance forward on + configuration data to the process monitor if the plugin needs/wants + to configure the feature. Plugins may call the new Process method + + ```C++ + virtual Error + ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp) + ``` + + where `type_name` is the feature name and `config_sp` points to the + configuration structured data, which may be nullptr. + +* Plugins for features present in a process are notified when modules + are loaded into the Process instance via this StructuredDataPlugin + method: + + ```C++ + virtual void + ModulesDidLoad(Process &process, ModuleList &module_list); + ``` + +* Plugins may optionally broadcast their received structured data as + an LLDB process-level event via the following new Process call: + + ```C++ + void + BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, + const lldb::StructuredDataPluginSP &plugin_sp); + ``` + + IDE clients might use this feature to receive information about the + process as it is running to monitor memory usage, CPU usage, and + logging. + + Internally, the event type created is an instance of + EventDataStructuredData. + +* In the case where a plugin chooses to broadcast a received + StructuredData event, the command-line LLDB Debugger instance + listens for them. The Debugger instance then gives the plugin an + opportunity to display info to either the debugger output or error + stream at a time that is safe to write to them. The plugin can + choose to display something appropriate regarding the structured + data that time. + +* Plugins can provide a ProcessLaunchInfo filter method when the + plugin is registered. If such a filter method is provided, then + when a process is about to be launched for debugging, the filter + callback is invoked, given both the launch info and the target. The + plugin may then alter the launch info if needed to better support + the feature of the plugin. + +* The plugin is entirely independent of the type of Process-derived + class that it is working with. The only requirements from the + process monitor are the following feature-agnostic elements: + + * Provide a way to discover features supported by the process + monitor for the current process. + + * Specify the list of supported feature type names to Process. + The process monitor does this by calling the following new + method on Process: + + ```C++ + void + MapSupportedStructuredDataPlugins(const StructuredData::Array + &supported_type_names) + ``` + + The `supported_type_names` specifies an array of string entries, + where each entry specifies the name of a StructuredData feature. + + * Provide a way to forward on configuration data for a feature type + to the process monitor. This is the manner by which LLDB can + configure a feature, perhaps based on settings or commands from + the user. The following virtual method on Process (described + earlier) does the job: + + ```C++ + virtual Error + ConfigureStructuredData(const ConstString &type_name, + const StructuredData::ObjectSP &config_sp) + ``` + + * Listen for asynchronous structured data packets from the process + monitor, and forward them on to Process via this new Process + member method: + + ```C++ + bool + RouteAsyncStructuredData(const StructuredData::ObjectSP object_sp) + ``` + +* StructuredData producers must send their top-level data as a + Dictionary type, with a key called 'type' specifying a string value, + where the value is equal to the StructuredData feature/type name + previously advertised. Everything else about the content of the + dictionary is entirely up to the feature. + +* StructuredDataPlugin commands show up under `plugin structured-data + plugin-name`. + +* StructuredDataPlugin settings show up under + `plugin.structured-data.{plugin-name}`. diff --git a/docs/testsuite/2010-10-19-14_10_49.059609/TestSettings.SettingsCommandTestCase.test_set_output_path.log b/docs/testsuite/2010-10-19-14_10_49.059609/TestSettings.SettingsCommandTestCase.test_set_output_path.log new file mode 100644 index 000000000..e18199537 --- /dev/null +++ b/docs/testsuite/2010-10-19-14_10_49.059609/TestSettings.SettingsCommandTestCase.test_set_output_path.log @@ -0,0 +1,43 @@ + +os command: [['/bin/sh', '-c', 'make clean; make']] +stdout: rm -rf "a.out" "a.out.dSYM" main.o main.d +g++ -arch x86_64 -gdwarf-2 -O0 -c -o main.o main.cpp +g++ -arch x86_64 -gdwarf-2 -O0 main.o -o "a.out" +/usr/bin/dsymutil -o "a.out.dSYM" "a.out" + +stderr: None +retcode: 0 + + +runCmd: file /Volumes/data/lldb/svn/trunk/test/settings/a.out +output: Current executable set to '/Volumes/data/lldb/svn/trunk/test/settings/a.out' (x86_64). + + +runCmd: settings set target.process.output-path 'stdout.txt' +output: + +runCmd: settings show target.process.output-path +output: target.process.output-path (string) = 'stdout.txt' + + +Expecting start string: target.process.output-path (string) = 'stdout.txt' +Matched + +runCmd: run +output: Process 43533 launched: '/Volumes/data/lldb/svn/trunk/test/settings/a.out' (x86_64) + + +FAIL + +runCmd: process kill +check of return status not required +runCmd failed! +error: Process must be launched. + + +Traceback (most recent call last): + File "/Volumes/data/lldb/svn/trunk/test/settings/TestSettings.py", line 125, in test_set_output_path + "'stdout.txt' exists due to target.process.output-path.") +AssertionError: False is not True : 'stdout.txt' exists due to target.process.output-path. + + diff --git a/docs/testsuite/a-detailed-walkthrough.txt b/docs/testsuite/a-detailed-walkthrough.txt new file mode 100644 index 000000000..6b5267f41 --- /dev/null +++ b/docs/testsuite/a-detailed-walkthrough.txt @@ -0,0 +1,309 @@ +Let's pick test/settings/TestSettings.py as our example. First, notice the file +name "TestSettings.py", the Test*.py pattern is the default mechanism that the +test driver uses for discovery of tests. As to TestSettings.py, it defines a +class: + +class SettingsCommandTestCase(TestBase): + +derived from TestBase, which is defined in test/lldbtest.py and is itself +derived from Python's unittest framework's TestCase class. See also +http://docs.python.org/library/unittest.html for more details. + +To just run the TestSettings.py test, chdir to the lldb test directory, and then +type the following command: + +/Volumes/data/lldb/svn/trunk/test $ ./dotest.py settings +---------------------------------------------------------------------- +Collected 6 tests + +---------------------------------------------------------------------- +Ran 6 tests in 8.699s + +OK (expected failures=1) +/Volumes/data/lldb/svn/trunk/test $ + +Pass '-v' option to the test driver to also output verbose descriptions of the +individual test cases and their test status: + +/Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings +---------------------------------------------------------------------- +Collected 6 tests + +test_set_auto_confirm (TestSettings.SettingsCommandTestCase) +Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok +test_set_output_path (TestSettings.SettingsCommandTestCase) +Test that setting target.process.output-path for the launched process works. ... expected failure +test_set_prompt (TestSettings.SettingsCommandTestCase) +Test that 'set prompt' actually changes the prompt. ... ok +test_set_term_width (TestSettings.SettingsCommandTestCase) +Test that 'set term-width' actually changes the term-width. ... ok +test_with_dsym (TestSettings.SettingsCommandTestCase) +Test that run-args and env-vars are passed to the launched process. ... ok +test_with_dwarf (TestSettings.SettingsCommandTestCase) +Test that run-args and env-vars are passed to the launched process. ... ok + +---------------------------------------------------------------------- +Ran 6 tests in 5.735s + +OK (expected failures=1) +/Volumes/data/lldb/svn/trunk/test $ + +Underneath, the '-v' option passes keyword argument verbosity=2 to the +Python's unittest.TextTestRunner (see also +http://docs.python.org/library/unittest.html#unittest.TextTestRunner). For very +detailed descriptions about what's going on during the test, pass '-t' to the +test driver, which asks the test driver to trace the commands executed and to +display their output. For brevity, the '-t' output is not included here. + +Notice the 'expected failures=1' message at the end of the run. This is because +of a bug currently in lldb such that setting target.process.output-path to +'stdout.txt' does not have any effect on the redirection of the standard output +of the subsequent launched process. We are using unittest2 (a backport of new +unittest features for Python 2.4-2.6) to decorate (mark) the particular test +method as such: + + @unittest2.expectedFailure + # rdar://problem/8435794 + # settings set target.process.output-path does not seem to work + def test_set_output_path(self): + +See http://pypi.python.org/pypi/unittest2 for more details. + +Now let's look inside the test method: + + def test_set_output_path(self): + """Test that setting target.process.output-path for the launched process works.""" + self.buildDefault() + + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # Set the output-path and verify it is set. + self.runCmd("settings set target.process.output-path 'stdout.txt'") + self.expect("settings show target.process.output-path", + startstr = "target.process.output-path (string) = 'stdout.txt'") + + self.runCmd("run", RUN_SUCCEEDED) + + # The 'stdout.txt' file should now exist. + self.assertTrue(os.path.isfile("stdout.txt"), + "'stdout.txt' exists due to target.process.output-path.") + + # Read the output file produced by running the program. + with open('stdout.txt', 'r') as f: + output = f.read() + + self.expect(output, exe=False, + startstr = "This message should go to standard out.") + +The self.buildDefault() statement is used to build a default binary for this +test instance. For this particular test case, since we don't really care what +debugging format is used, we instruct the build subsystem to build the default +binary for us. The base class TestBase has defined three instance methods: + + def buildDefault(self, architecture=None, compiler=None, dictionary=None): + """Platform specific way to build the default binaries.""" + module = __import__(sys.platform) + if not module.buildDefault(self, architecture, compiler, dictionary): + raise Exception("Don't know how to build default binary") + + def buildDsym(self, architecture=None, compiler=None, dictionary=None): + """Platform specific way to build binaries with dsym info.""" + module = __import__(sys.platform) + if not module.buildDsym(self, architecture, compiler, dictionary): + raise Exception("Don't know how to build binary with dsym") + + def buildDwarf(self, architecture=None, compiler=None, dictionary=None): + """Platform specific way to build binaries with dwarf maps.""" + module = __import__(sys.platform) + if not module.buildDwarf(self, architecture, compiler, dictionary): + raise Exception("Don't know how to build binary with dwarf") + +And the test/plugins/darwin.py provides the implementation for all three build +methods using the makefile mechanism. We envision that linux plugin can use a +similar approach to accomplish the task of building the binaries. + +Mac OS X provides an additional way to manipulate archived DWARF debug symbol +files and produces dSYM files. The buildDsym() instance method is used by the +test method to build the binary with dsym info. For an example of this, +see test/array_types/TestArrayTypes.py: + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + def test_with_dsym_and_run_command(self): + """Test 'frame variable var_name' on some variables with array types.""" + self.buildDsym() + self.array_types() + +This method is decorated with a skipUnless decorator so that it will only gets +included into the test suite if the platform it is running on is 'darwin', aka +Mac OS X. + +Type 'man dsymutil' for more details. + +After the binary is built, it is time to specify the file to be used as the main +executable by lldb: + + exe = os.path.join(os.getcwd(), "a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + +This is where the attribute assignment: + +class SettingsCommandTestCase(TestBase): + + mydir = "settings" + +which happens right after the SettingsCommandTestCase class declaration comes +into place. It specifies the relative directory to the top level 'test' so that +the test harness can change its working directory in order to find the +executable as well as the source code files. The runCmd() method is defined in +the TestBase base class (within test/lldbtest.py) and its purpose is to pass the +specified command to the lldb command interpreter. It's like you're typing the +command within an interactive lldb session. + +The CURRENT_EXECUTABLE_SET is an assert message defined in the lldbtest module +so that it can be reused from other test modules. + +By default, the runCmd() is going to check the return status of the command +execution and fails the test if it is not a success. The assert message, in our +case CURRENT_EXECUTABLE_SET, is used in the exception printout if this happens. + +There are cases when we don't care about the return status from the command +execution. This can be accomplished by passing the keyword argument pair +'check=False' to the method. + +After the current executable is set, we'll then execute two more commands: + + # Set the output-path and verify it is set. + self.runCmd("settings set target.process.output-path 'stdout.txt'") + self.expect("settings show target.process.output-path", + SETTING_MSG("target.process.output-path"), + startstr = "target.process.output-path (string) = 'stdout.txt'") + +The first uses the 'settings set' command to set the static setting +target.process.output-path to be 'stdout.txt', instead of the default +'/dev/stdout'. We then immediately issue a 'settings show' command to check +that, indeed, the setting did take place. Notice that we use a new method +expect() to accomplish the task, which in effect issues a runCmd() behind the +door and grabs the output from the command execution and expects to match the +start string of the output against what we pass in as the value of the keyword +argument pair: + + startstr = "target.process.output-path (string) = 'stdout.txt'" + +Take a look at TestBase.expect() within lldbtest.py for more details. Among +other things, it can also match against a list of regexp patterns as well as a +list of sub strings. And it can also perform negative matching, i.e., instead +of expecting something from the output of command execution, it can perform the +action of 'not expecting' something. + +This will launch/run the program: + + self.runCmd("run", RUN_SUCCEEDED) + +And this asserts that the file 'stdout.txt' should be present after running the +program. + + # The 'stdout.txt' file should now exist. + self.assertTrue(os.path.isfile("stdout.txt"), + "'stdout.txt' exists due to target.process.output-path.") + +Also take a look at main.cpp which emits some message to the stdout. Now, if we +pass this assertion, it's time to examine the contents of the file to make sure +it contains the same message as programmed in main.cpp: + + # Read the output file produced by running the program. + with open('stdout.txt', 'r') as f: + output = f.read() + + self.expect(output, exe=False, + startstr = "This message should go to standard out.") + +We open the file and read its contents into output, then issue an expect() +method. The 'exe=False' keyword argument pair tells expect() that don't try to +execute the first arg as a command at all. Instead, treat it as a string to +match against whatever is thrown in as keyword argument pairs! + +There are also other test methods present in the TestSettings.py mode: +test_set_prompt(), test_set_term_width(), test_set_auto_confirm(), +test_with_dsym(), and test_with_dwarf(). We are using the default test loader +from unittest framework, which uses the 'test' method name prefix to identify +test methods automatically. + +This finishes the walkthrough of the test method test_set_output_path(self). +Before we say goodbye, notice the little method definition at the top of the +file: + + @classmethod + def classCleanup(cls): + system(["/bin/sh", "-c", "rm -f output.txt"]) + system(["/bin/sh", "-c", "rm -f stdout.txt"]) + +This is a classmethod (as shown by the @classmethod decorator) which allows the +individual test class to perform cleanup actions after the test harness finishes +with the particular test class. This is part of the so-called test fixture in +the unittest framework. From http://docs.python.org/library/unittest.html: + +A test fixture represents the preparation needed to perform one or more tests, +and any associate cleanup actions. This may involve, for example, creating +temporary or proxy databases, directories, or starting a server process. + +The TestBase class uses such fixture with setUp(self), tearDown(self), +setUpClass(cls), and tearDownClass(cls). And within teraDownClass(cls), it +checks whether the current class has an attribute named 'classCleanup', and +executes as a method if present. In this particular case, the classCleanup() +calls a utility function system() defined in lldbtest.py in order to remove the +files created by running the program as the tests are executed. + +This system() function uses the Python subprocess module to spawn the process +and to retrieve its results. If the test instance passes the keyword argument +pair 'sender=self', the detailed command execution through the operating system +also gets recorded in a session object. If the test instance fails or errors, +the session info automatically gets dumped to a file grouped under a directory +named after the timestamp of the particular test suite run. + +For simple cases, look for the timestamp directory in the same directory of the +test driver program dotest.py. For example, if we comment out the +@expectedFailure decorator for TestSettings.py, and then run the test module: + +/Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings +---------------------------------------------------------------------- +Collected 6 tests + +test_set_auto_confirm (TestSettings.SettingsCommandTestCase) +Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok +test_set_output_path (TestSettings.SettingsCommandTestCase) +Test that setting target.process.output-path for the launched process works. ... FAIL +test_set_prompt (TestSettings.SettingsCommandTestCase) +Test that 'set prompt' actually changes the prompt. ... ok +test_set_term_width (TestSettings.SettingsCommandTestCase) +Test that 'set term-width' actually changes the term-width. ... ok +test_with_dsym (TestSettings.SettingsCommandTestCase) +Test that run-args and env-vars are passed to the launched process. ... ok +test_with_dwarf (TestSettings.SettingsCommandTestCase) +Test that run-args and env-vars are passed to the launched process. ... ok + +====================================================================== +FAIL: test_set_output_path (TestSettings.SettingsCommandTestCase) +Test that setting target.process.output-path for the launched process works. +---------------------------------------------------------------------- +Traceback (most recent call last): + File "/Volumes/data/lldb/svn/trunk/test/settings/TestSettings.py", line 125, in test_set_output_path + "'stdout.txt' exists due to target.process.output-path.") +AssertionError: False is not True : 'stdout.txt' exists due to target.process.output-path. + +---------------------------------------------------------------------- +Ran 6 tests in 8.219s + +FAILED (failures=1) +/Volumes/data/lldb/svn/trunk/test $ ls 2010-10-19-14:10:49.059609 + +NOTE: This directory name has been changed to not contain the ':' character + which is not allowed in windows platforms. We'll change the ':' to '_' + and get rid of the microsecond resolution by modifying the test driver. + +TestSettings.SettingsCommandTestCase.test_set_output_path.log +/Volumes/data/lldb/svn/trunk/test $ + +We get one failure and a timestamp directory 2010-10-19-14:10:49.059609. +For education purposes, the directory and its contents are reproduced here in +the same directory as the current file. diff --git a/docs/testsuite/best-practices.txt b/docs/testsuite/best-practices.txt new file mode 100644 index 000000000..b5a9156fd --- /dev/null +++ b/docs/testsuite/best-practices.txt @@ -0,0 +1,93 @@ +This document attempts to point out some best practices that prove to be helpful +when building new test cases in the tot/test directory. Everyone is welcomed to +add/modify contents into this file. + +o Do not use hard-coded line numbers in your test case. Instead, try to tag the + line with some distinguishing pattern, and use the function line_number() + defined in lldbtest.py which takes filename and string_to_match as arguments + and returns the line number. + +As an example, take a look at test/breakpoint_conditions/main.c which has these +two lines: + + return c(val); // Find the line number of c's parent call here. + +and + + return val + 3; // Find the line number of function "c" here. + +The Python test case TestBreakpointConditions.py uses the comment strings to +find the line numbers during setUp(self) and use them later on to verify that +the correct breakpoint is being stopped on and that its parent frame also has +the correct line number as intended through the breakpoint condition. + +o Take advantage of the unittest framework's decorator features to properly + mark your test class or method for platform-specific tests. + +As an example, take a look at test/forward/TestForwardDeclaration.py which has +these lines: + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + def test_with_dsym_and_run_command(self): + """Display *bar_ptr when stopped on a function with forward declaration of struct bar.""" + self.buildDsym() + self.forward_declaration() + +This tells the test harness that unless we are running "darwin", the test should +be skipped. This is because we are asking to build the binaries with dsym debug +info, which is only available on the darwin platforms. + +o Cleanup after yourself. A classic example of this can be found in test/types/ + TestFloatTypes.py: + + def test_float_types_with_dsym(self): + """Test that float-type variables are displayed correctly.""" + d = {'CXX_SOURCES': 'float.cpp'} + self.buildDsym(dictionary=d) + self.setTearDownCleanup(dictionary=d) + self.float_type() + + ... + + def test_double_type_with_dsym(self): + """Test that double-type variables are displayed correctly.""" + d = {'CXX_SOURCES': 'double.cpp'} + self.buildDsym(dictionary=d) + self.setTearDownCleanup(dictionary=d) + self.double_type() + +This tests different data structures composed of float types to verify that what +the debugger prints out matches what the compiler does for different variables +of these types. We're using a dictionary to pass the build parameters to the +build system. After a particular test instance is done, it is a good idea to +clean up the files built. This eliminates the chance that some leftover files +can interfere with the build phase for the next test instance and render it +invalid. + +TestBase.setTearDownCleanup(self, dictionary) defined in lldbtest.py is created +to cope with this use case by taking the same build parameters in order to do +the cleanup when we are finished with a test instance, during +TestBase.tearDown(self). + +o Class-wise cleanup after yourself. + +TestBase.tearDownClass(cls) provides a mechanism to invoke the platform-specific +cleanup after finishing with a test class. A test class can have more than one +test methods, so the tearDownClass(cls) method gets run after all the test +methods have been executed by the test harness. + +The default cleanup action performed by the plugins/darwin.py module invokes the +"make clean" os command. + +If this default cleanup is not enough, individual class can provide an extra +cleanup hook with a class method named classCleanup , for example, +in test/breakpoint_command/TestBreakpointCommand.py: + + @classmethod + def classCleanup(cls): + system(["/bin/sh", "-c", "rm -f output.txt"]) + +The 'output.txt' file gets generated during the test run, so it makes sense to +explicitly spell out the action in the same TestBreakpointCommand.py file to do +the cleanup instead of artificially adding it as part of the default cleanup +action which serves to cleanup those intermediate and a.out files. diff --git a/examples/customization/bin-utils/.lldbinit b/examples/customization/bin-utils/.lldbinit new file mode 100644 index 000000000..5a2f6feb9 --- /dev/null +++ b/examples/customization/bin-utils/.lldbinit @@ -0,0 +1,5 @@ +# So that ~/binutils.py takes precedence. +script sys.path[:0] = [os.path.expanduser('~')] +script import binutils +command script add -f binutils.itob itob +command script add -f binutils.utob utob diff --git a/examples/customization/bin-utils/README b/examples/customization/bin-utils/README new file mode 100644 index 000000000..1352d93b2 --- /dev/null +++ b/examples/customization/bin-utils/README @@ -0,0 +1,36 @@ +Files in this directory: + +o .lldbinit: + +An example lldb init file that imports the binutils.py module and adds the +following commands: 'itob' and 'utob'. + +o binutils.py: + +Python module which provides implementation for the 'itob' and 'utob' commands. + +o README: + +The file you are reading now. + +================================================================================ +The following terminal output shows an interaction with lldb using the .lldbinit +and the binutils.py files which are located in my HOME directory. The lldb init +file imports the utils Python module and adds the 'itob' and 'utob' commands. + +$ /Volumes/data/lldb/svn/trunk/build/Debug/lldb +(lldb) help itob +Convert the integer to print its two's complement representation. + args[0] (mandatory) is the integer to be converted + args[1] (mandatory) is the bit width of the two's complement representation + args[2] (optional) if specified, turns on verbose printing +Syntax: itob +(lldb) itob -5 4 + [1, 0, 1, 1] +(lldb) itob -5 32 v + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1] +(lldb) utob 0xABCD 32 v + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1] +(lldb) diff --git a/examples/customization/bin-utils/binutils.py b/examples/customization/bin-utils/binutils.py new file mode 100644 index 000000000..576dcba02 --- /dev/null +++ b/examples/customization/bin-utils/binutils.py @@ -0,0 +1,125 @@ +"Collection of tools for displaying bit representation of numbers.""" + +import StringIO + + +def binary(n, width=None): + """ + Return a list of (0|1)'s for the binary representation of n where n >= 0. + If you specify a width, it must be > 0, otherwise it is ignored. The list + could be padded with 0 bits if width is specified. + """ + l = [] + if width and width <= 0: + width = None + while n > 0: + l.append(1 if n & 1 else 0) + n = n >> 1 + + if width: + for i in range(width - len(l)): + l.append(0) + + l.reverse() + return l + + +def twos_complement(n, width): + """ + Return a list of (0|1)'s for the binary representation of a width-bit two's + complement numeral system of an integer n which may be negative. + """ + val = 2**(width - 1) + if n >= 0: + if n > (val - 1): + return None + # It is safe to represent n with width-bits. + return binary(n, width) + + if n < 0: + if abs(n) > val: + return None + # It is safe to represent n (a negative int) with width-bits. + return binary(val * 2 - abs(n)) + +# print binary(0xABCD) +# [1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1] +# print binary(0x1F, 8) +# [0, 0, 0, 1, 1, 1, 1, 1] +# print twos_complement(-5, 4) +# [1, 0, 1, 1] +# print twos_complement(7, 4) +# [0, 1, 1, 1] +# print binary(7) +# [1, 1, 1] +# print twos_complement(-5, 64) +# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1] + + +def positions(width): + """Helper function returning a list describing the bit positions. + Bit positions greater than 99 are truncated to 2 digits, for example, + 100 -> 00 and 127 -> 27.""" + return ['{0:2}'.format(i)[-2:] for i in reversed(range(width))] + + +def utob(debugger, command_line, result, dict): + """Convert the unsigned integer to print its binary representation. + args[0] (mandatory) is the unsigned integer to be converted + args[1] (optional) is the bit width of the binary representation + args[2] (optional) if specified, turns on verbose printing""" + args = command_line.split() + try: + n = int(args[0], 0) + width = None + if len(args) > 1: + width = int(args[1], 0) + if width < 0: + width = 0 + except: + print utob.__doc__ + return + + if len(args) > 2: + verbose = True + else: + verbose = False + + bits = binary(n, width) + if not bits: + print "insufficient width value: %d" % width + return + if verbose and width > 0: + pos = positions(width) + print ' ' + ' '.join(pos) + print ' %s' % str(bits) + + +def itob(debugger, command_line, result, dict): + """Convert the integer to print its two's complement representation. + args[0] (mandatory) is the integer to be converted + args[1] (mandatory) is the bit width of the two's complement representation + args[2] (optional) if specified, turns on verbose printing""" + args = command_line.split() + try: + n = int(args[0], 0) + width = int(args[1], 0) + if width < 0: + width = 0 + except: + print itob.__doc__ + return + + if len(args) > 2: + verbose = True + else: + verbose = False + + bits = twos_complement(n, width) + if not bits: + print "insufficient width value: %d" % width + return + if verbose and width > 0: + pos = positions(width) + print ' ' + ' '.join(pos) + print ' %s' % str(bits) diff --git a/examples/customization/import-python/README b/examples/customization/import-python/README new file mode 100644 index 000000000..9122f8f46 --- /dev/null +++ b/examples/customization/import-python/README @@ -0,0 +1,40 @@ +Files in this directory: + +o importcmd.py: + +Python module which provides implementation for the 'import' command. + +o README: + +The file you are reading now. + +================================================================================ +The import command defined by importcmd.py can be used in LLDB to load a Python +module given its full pathname. +The command works by extending Python's sys.path lookup to include the path to +the module to be imported when required, and then going through the language +ordinary 'import' mechanism. In this respect, modules imported from LLDB command +line should not be distinguishable from those imported using the script interpreter. +The following terminal output shows an interaction with lldb using this new command. + +Enrico-Granatas-MacBook-Pro:Debug enricogranata$ ./lldb +(lldb) script import importcmd +(lldb) command script add import -f importcmd.pyimport_cmd +(lldb) import ../demo.py +(lldb) script demo.test_function('hello world') +I am a Python function that says hello world +(lldb) quit +Enrico-Granatas-MacBook-Pro:Debug enricogranata$ + +Of course, the commands to import the importcmd.py module and to define the import +command, can be included in the .lldbinit file to make this feature available at +debugger startup + +WARNING: The import command defined by importcmd.py is now obsolete +In TOT LLDB, you can say: +(lldb) command script import ../demo.py +(lldb) script demo.test_function('hello world') +I am a Python function that says hello world +(lldb) quit + +using the native "command script import" command, which offers a superset of what the import command provided by importcmd.py does diff --git a/examples/customization/import-python/importcmd.py b/examples/customization/import-python/importcmd.py new file mode 100644 index 000000000..1d47ad213 --- /dev/null +++ b/examples/customization/import-python/importcmd.py @@ -0,0 +1,38 @@ +import sys +import os +import lldb + + +def check_has_dir_in_path(dirname): + return sys.path.__contains__(dirname) + + +def ensure_has_dir_in_path(dirname): + dirname = os.path.abspath(dirname) + if not (check_has_dir_in_path(dirname)): + sys.path.append(dirname) + + +def do_import(debugger, modname): + if (len(modname) > 4 and modname[-4:] == '.pyc'): + modname = modname[:-4] + if (len(modname) > 3 and modname[-3:] == '.py'): + modname = modname[:-3] + debugger.HandleCommand("script import " + modname) + + +def pyimport_cmd(debugger, args, result, dict): + """Import a Python module given its full path""" + print 'WARNING: obsolete feature - use native command "command script import"' + if args == "": + return "no module path given" + if not (os.sep in args): + modname = args + ensure_has_dir_in_path('.') + else: + endofdir = args.rfind(os.sep) + modname = args[endofdir + 1:] + args = args[0:endofdir] + ensure_has_dir_in_path(args) + do_import(debugger, modname) + return None diff --git a/examples/customization/pwd-cd-and-system/.lldbinit b/examples/customization/pwd-cd-and-system/.lldbinit new file mode 100644 index 000000000..f477b5797 --- /dev/null +++ b/examples/customization/pwd-cd-and-system/.lldbinit @@ -0,0 +1,7 @@ +script import os, sys +# So that ~/utils.py takes precedence. +script sys.path[:0] = [os.path.expanduser('~')] +script import utils +command alias pwd script print os.getcwd() +command script add -f utils.chdir cd +command script add -f utils.system system diff --git a/examples/customization/pwd-cd-and-system/README b/examples/customization/pwd-cd-and-system/README new file mode 100644 index 000000000..1b67d0b09 --- /dev/null +++ b/examples/customization/pwd-cd-and-system/README @@ -0,0 +1,41 @@ +Files in this directory: + +o .lldbinit: + +An example lldb init file that imports the utils.py module and adds the +following commands: 'pwd', 'cd', and 'system'. + +o utils.py: + +Python module which provides implementation for the 'cd' and 'system' commands. + +o README: + +The file you are reading now. + +================================================================================ +The following terminal output shows an interaction with lldb using the .lldbinit +and the utils.py files which are located in my HOME directory. The lldb init +file imports the utils Python module and adds the 'pwd', 'cd', and 'system' +commands. + +Johnnys-MacBook-Pro:multiple_threads johnny$ pwd +/Volumes/data/lldb/svn/trunk/test/functionalities/watchpoint/multiple_threads +Johnnys-MacBook-Pro:multiple_threads johnny$ lldb +(lldb) pwd +/Volumes/data/lldb/svn/trunk/test/functionalities/watchpoint/multiple_threads +(lldb) cd .. +Current working directory: /Volumes/data/lldb/svn/trunk/test/functionalities/watchpoint +(lldb) help system + +Execute the command (a string) in a subshell. +Syntax: system +(lldb) system ls -l +total 0 +drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 hello_watchlocation +drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 hello_watchpoint +drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 multiple_threads +drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 watchpoint_commands + +retcode: 0 +(lldb) diff --git a/examples/customization/pwd-cd-and-system/utils.py b/examples/customization/pwd-cd-and-system/utils.py new file mode 100644 index 000000000..6e3462e1c --- /dev/null +++ b/examples/customization/pwd-cd-and-system/utils.py @@ -0,0 +1,58 @@ +"""Utility for changing directories and execution of commands in a subshell.""" + +import os +import shlex +import subprocess + +# Store the previous working directory for the 'cd -' command. + + +class Holder: + """Holds the _prev_dir_ class attribute for chdir() function.""" + _prev_dir_ = None + + @classmethod + def prev_dir(cls): + return cls._prev_dir_ + + @classmethod + def swap(cls, dir): + cls._prev_dir_ = dir + + +def chdir(debugger, args, result, dict): + """Change the working directory, or cd to ${HOME}. + You can also issue 'cd -' to change to the previous working directory.""" + new_dir = args.strip() + if not new_dir: + new_dir = os.path.expanduser('~') + elif new_dir == '-': + if not Holder.prev_dir(): + # Bad directory, not changing. + print "bad directory, not changing" + return + else: + new_dir = Holder.prev_dir() + + Holder.swap(os.getcwd()) + os.chdir(new_dir) + print "Current working directory: %s" % os.getcwd() + + +def system(debugger, command_line, result, dict): + """Execute the command (a string) in a subshell.""" + args = shlex.split(command_line) + process = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + output, error = process.communicate() + retcode = process.poll() + if output and error: + print "stdout=>\n", output + print "stderr=>\n", error + elif output: + print output + elif error: + print error + print "retcode:", retcode diff --git a/examples/darwin/heap_find/heap.py b/examples/darwin/heap_find/heap.py new file mode 100644 index 000000000..2189077a4 --- /dev/null +++ b/examples/darwin/heap_find/heap.py @@ -0,0 +1,1522 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# This module is designed to live inside the "lldb" python package +# in the "lldb.macosx" package. To use this in the embedded python +# interpreter using "lldb" just import it: +# +# (lldb) script import lldb.macosx.heap +#---------------------------------------------------------------------- + +import lldb +import commands +import optparse +import os +import os.path +import re +import shlex +import string +import sys +import tempfile +import lldb.utils.symbolication + +g_libheap_dylib_dir = None +g_libheap_dylib_dict = dict() + + +def get_iterate_memory_expr( + options, + process, + user_init_code, + user_return_code): + expr = ''' +typedef unsigned natural_t; +typedef uintptr_t vm_size_t; +typedef uintptr_t vm_address_t; +typedef natural_t task_t; +typedef int kern_return_t; +#define KERN_SUCCESS 0 +typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size); +''' + if options.search_vm_regions: + expr += ''' +typedef int vm_prot_t; +typedef unsigned int vm_inherit_t; +typedef unsigned long long memory_object_offset_t; +typedef unsigned int boolean_t; +typedef int vm_behavior_t; +typedef uint32_t vm32_object_id_t; +typedef natural_t mach_msg_type_number_t; +typedef uint64_t mach_vm_address_t; +typedef uint64_t mach_vm_offset_t; +typedef uint64_t mach_vm_size_t; +typedef uint64_t vm_map_offset_t; +typedef uint64_t vm_map_address_t; +typedef uint64_t vm_map_size_t; +#define VM_PROT_NONE ((vm_prot_t) 0x00) +#define VM_PROT_READ ((vm_prot_t) 0x01) +#define VM_PROT_WRITE ((vm_prot_t) 0x02) +#define VM_PROT_EXECUTE ((vm_prot_t) 0x04) +typedef struct vm_region_submap_short_info_data_64_t { + vm_prot_t protection; + vm_prot_t max_protection; + vm_inherit_t inheritance; + memory_object_offset_t offset; // offset into object/map + unsigned int user_tag; // user tag on map entry + unsigned int ref_count; // obj/map mappers, etc + unsigned short shadow_depth; // only for obj + unsigned char external_pager; // only for obj + unsigned char share_mode; // see enumeration + boolean_t is_submap; // submap vs obj + vm_behavior_t behavior; // access behavior hint + vm32_object_id_t object_id; // obj/map name, not a handle + unsigned short user_wired_count; +} vm_region_submap_short_info_data_64_t; +#define VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 ((mach_msg_type_number_t)(sizeof(vm_region_submap_short_info_data_64_t)/sizeof(int)))''' + if user_init_code: + expr += user_init_code + expr += ''' +task_t task = (task_t)mach_task_self(); +mach_vm_address_t vm_region_base_addr; +mach_vm_size_t vm_region_size; +natural_t vm_region_depth; +vm_region_submap_short_info_data_64_t vm_region_info; +kern_return_t err; +for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; vm_region_base_addr += vm_region_size) +{ + mach_msg_type_number_t vm_region_info_size = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + err = (kern_return_t)mach_vm_region_recurse (task, + &vm_region_base_addr, + &vm_region_size, + &vm_region_depth, + &vm_region_info, + &vm_region_info_size); + if (err) + break; + // Check all read + write regions. This will cover the thread stacks + // and any regions of memory like __DATA segments, that might contain + // data we are looking for + if (vm_region_info.protection & VM_PROT_WRITE && + vm_region_info.protection & VM_PROT_READ) + { + baton.callback (task, + &baton, + 64, + vm_region_base_addr, + vm_region_size); + } +}''' + else: + if options.search_stack: + expr += get_thread_stack_ranges_struct(process) + if options.search_segments: + expr += get_sections_ranges_struct(process) + if user_init_code: + expr += user_init_code + if options.search_heap: + expr += ''' +#define MALLOC_PTR_IN_USE_RANGE_TYPE 1 +typedef struct vm_range_t { + vm_address_t address; + vm_size_t size; +} vm_range_t; +typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory); +typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size); +typedef struct malloc_introspection_t { + kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */ +} malloc_introspection_t; +typedef struct malloc_zone_t { + void *reserved1[12]; + struct malloc_introspection_t *introspect; +} malloc_zone_t; +memory_reader_t task_peek = [](task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -> kern_return_t { + *local_memory = (void*) remote_address; + return KERN_SUCCESS; +}; +vm_address_t *zones = 0; +unsigned int num_zones = 0;task_t task = 0; +kern_return_t err = (kern_return_t)malloc_get_all_zones (task, task_peek, &zones, &num_zones); +if (KERN_SUCCESS == err) +{ + for (unsigned int i=0; iintrospect) + zone->introspect->enumerator (task, + &baton, + MALLOC_PTR_IN_USE_RANGE_TYPE, + (vm_address_t)zone, + task_peek, + [] (task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned size) -> void + { + range_callback_t callback = ((callback_baton_t *)baton)->callback; + for (unsigned i=0; i 0) { + range_callback(task, &baton, 16, stacks[i].base - STACK_RED_ZONE_SIZE, STACK_RED_ZONE_SIZE); + } +} +#endif''' + + if options.search_segments: + expr += ''' +#ifdef NUM_SEGMENTS +// Call the callback for all segments +for (uint32_t i=0; i 0 and var_addr <= match_addr and match_addr < ( + var_addr + byte_size): + if verbose: + print 'match' + return var + return None + + +def find_frame_for_stack_address(process, addr): + closest_delta = sys.maxsize + closest_frame = None + # print 'find_frame_for_stack_address(%#x)' % (addr) + for thread in process: + prev_sp = lldb.LLDB_INVALID_ADDRESS + for frame in thread: + cfa = frame.GetCFA() + # print 'frame #%u: cfa = %#x' % (frame.GetFrameID(), cfa) + if addr < cfa: + delta = cfa - addr + # print '%#x < %#x, delta = %i' % (addr, cfa, delta) + if delta < closest_delta: + # print 'closest' + closest_delta = delta + closest_frame = frame + # else: + # print 'delta >= closest_delta' + return closest_frame + + +def type_flags_to_description( + process, + type_flags, + ptr_addr, + ptr_size, + offset, + match_addr): + show_offset = False + if type_flags == 0 or type_flags & 4: + type_str = 'free(%#x)' % (ptr_addr,) + elif type_flags & 2 or type_flags & 1: + type_str = 'malloc(%6u) -> %#x' % (ptr_size, ptr_addr) + show_offset = True + elif type_flags & 8: + type_str = 'stack' + frame = find_frame_for_stack_address(process, match_addr) + if frame: + type_str += ' in frame #%u of thread #%u: tid %#x' % (frame.GetFrameID( + ), frame.GetThread().GetIndexID(), frame.GetThread().GetThreadID()) + variables = frame.GetVariables(True, True, True, True) + matching_var = None + for var in variables: + var_addr = var.GetLoadAddress() + if var_addr != lldb.LLDB_INVALID_ADDRESS: + # print 'variable "%s" @ %#x (%#x)' % (var.name, var.load_addr, + # match_addr) + if var_addr == match_addr: + matching_var = var + break + else: + byte_size = var.GetType().GetByteSize() + if byte_size > 0 and var_addr <= match_addr and match_addr < ( + var_addr + byte_size): + matching_var = var + break + if matching_var: + type_str += ' in variable at %#x:\n %s' % ( + matching_var.GetLoadAddress(), matching_var) + elif type_flags & 16: + type_str = 'stack (red zone)' + elif type_flags & 32: + sb_addr = process.GetTarget().ResolveLoadAddress(ptr_addr + offset) + type_str = 'segment [%#x - %#x), %s + %u, %s' % ( + ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr) + elif type_flags & 64: + sb_addr = process.GetTarget().ResolveLoadAddress(ptr_addr + offset) + type_str = 'vm_region [%#x - %#x), %s + %u, %s' % ( + ptr_addr, ptr_addr + ptr_size, sb_addr.section.name, sb_addr.offset, sb_addr) + else: + type_str = '%#x' % (ptr_addr,) + show_offset = True + if show_offset and offset != 0: + type_str += ' + %-6u' % (offset,) + return type_str + + +def dump_stack_history_entry(options, result, stack_history_entry, idx): + address = int(stack_history_entry.address) + if address: + type_flags = int(stack_history_entry.type_flags) + symbolicator = lldb.utils.symbolication.Symbolicator() + symbolicator.target = lldb.debugger.GetSelectedTarget() + type_str = type_flags_to_string(type_flags) + result.AppendMessage( + 'stack[%u]: addr = 0x%x, type=%s, frames:' % + (idx, address, type_str)) + frame_idx = 0 + idx = 0 + pc = int(stack_history_entry.frames[idx]) + while pc != 0: + if pc >= 0x1000: + frames = symbolicator.symbolicate(pc) + if frames: + for frame in frames: + result.AppendMessage( + ' [%u] %s' % + (frame_idx, frame)) + frame_idx += 1 + else: + result.AppendMessage(' [%u] 0x%x' % (frame_idx, pc)) + frame_idx += 1 + idx = idx + 1 + pc = int(stack_history_entry.frames[idx]) + else: + pc = 0 + if idx >= options.max_frames: + result.AppendMessage( + 'warning: the max number of stack frames (%u) was reached, use the "--max-frames=" option to see more frames' % + (options.max_frames)) + + result.AppendMessage('') + + +def dump_stack_history_entries(options, result, addr, history): + # malloc_stack_entry *get_stack_history_for_address (const void * addr) + expr_prefix = ''' +typedef int kern_return_t; +typedef struct $malloc_stack_entry { + uint64_t address; + uint64_t argument; + uint32_t type_flags; + uint32_t num_frames; + uint64_t frames[512]; + kern_return_t err; +} $malloc_stack_entry; +''' + single_expr = ''' +#define MAX_FRAMES %u +typedef unsigned task_t; +$malloc_stack_entry stack; +stack.address = 0x%x; +stack.type_flags = 2; +stack.num_frames = 0; +stack.frames[0] = 0; +uint32_t max_stack_frames = MAX_FRAMES; +stack.err = (kern_return_t)__mach_stack_logging_get_frames ( + (task_t)mach_task_self(), + stack.address, + &stack.frames[0], + max_stack_frames, + &stack.num_frames); +if (stack.num_frames < MAX_FRAMES) + stack.frames[stack.num_frames] = 0; +else + stack.frames[MAX_FRAMES-1] = 0; +stack''' % (options.max_frames, addr) + + history_expr = ''' +typedef int kern_return_t; +typedef unsigned task_t; +#define MAX_FRAMES %u +#define MAX_HISTORY %u +typedef struct mach_stack_logging_record_t { + uint32_t type_flags; + uint64_t stack_identifier; + uint64_t argument; + uint64_t address; +} mach_stack_logging_record_t; +typedef void (*enumerate_callback_t)(mach_stack_logging_record_t, void *); +typedef struct malloc_stack_entry { + uint64_t address; + uint64_t argument; + uint32_t type_flags; + uint32_t num_frames; + uint64_t frames[MAX_FRAMES]; + kern_return_t frames_err; +} malloc_stack_entry; +typedef struct $malloc_stack_history { + task_t task; + unsigned idx; + malloc_stack_entry entries[MAX_HISTORY]; +} $malloc_stack_history; +$malloc_stack_history info = { (task_t)mach_task_self(), 0 }; +uint32_t max_stack_frames = MAX_FRAMES; +enumerate_callback_t callback = [] (mach_stack_logging_record_t stack_record, void *baton) -> void { + $malloc_stack_history *info = ($malloc_stack_history *)baton; + if (info->idx < MAX_HISTORY) { + malloc_stack_entry *stack_entry = &(info->entries[info->idx]); + stack_entry->address = stack_record.address; + stack_entry->type_flags = stack_record.type_flags; + stack_entry->argument = stack_record.argument; + stack_entry->num_frames = 0; + stack_entry->frames[0] = 0; + stack_entry->frames_err = (kern_return_t)__mach_stack_logging_frames_for_uniqued_stack ( + info->task, + stack_record.stack_identifier, + stack_entry->frames, + (uint32_t)MAX_FRAMES, + &stack_entry->num_frames); + // Terminate the frames with zero if there is room + if (stack_entry->num_frames < MAX_FRAMES) + stack_entry->frames[stack_entry->num_frames] = 0; + } + ++info->idx; +}; +(kern_return_t)__mach_stack_logging_enumerate_records (info.task, (uint64_t)0x%x, callback, &info); +info''' % (options.max_frames, options.max_history, addr) + + frame = lldb.debugger.GetSelectedTarget().GetProcess( + ).GetSelectedThread().GetSelectedFrame() + if history: + expr = history_expr + else: + expr = single_expr + expr_options = lldb.SBExpressionOptions() + expr_options.SetIgnoreBreakpoints(True) + expr_options.SetTimeoutInMicroSeconds(5 * 1000 * 1000) # 5 second timeout + expr_options.SetTryAllThreads(True) + expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) + expr_options.SetPrefix(expr_prefix) + expr_sbvalue = frame.EvaluateExpression(expr, expr_options) + if options.verbose: + print "expression:" + print expr + print "expression result:" + print expr_sbvalue + if expr_sbvalue.error.Success(): + if history: + malloc_stack_history = lldb.value(expr_sbvalue) + num_stacks = int(malloc_stack_history.idx) + if num_stacks <= options.max_history: + i_max = num_stacks + else: + i_max = options.max_history + for i in range(i_max): + stack_history_entry = malloc_stack_history.entries[i] + dump_stack_history_entry( + options, result, stack_history_entry, i) + if num_stacks > options.max_history: + result.AppendMessage( + 'warning: the max number of stacks (%u) was reached, use the "--max-history=%u" option to see all of the stacks' % + (options.max_history, num_stacks)) + else: + stack_history_entry = lldb.value(expr_sbvalue) + dump_stack_history_entry(options, result, stack_history_entry, 0) + + else: + result.AppendMessage( + 'error: expression failed "%s" => %s' % + (expr, expr_sbvalue.error)) + + +def display_match_results( + process, + result, + options, + arg_str_description, + expr, + print_no_matches, + expr_prefix=None): + frame = lldb.debugger.GetSelectedTarget().GetProcess( + ).GetSelectedThread().GetSelectedFrame() + if not frame: + result.AppendMessage('error: invalid frame') + return 0 + expr_options = lldb.SBExpressionOptions() + expr_options.SetIgnoreBreakpoints(True) + expr_options.SetFetchDynamicValue(lldb.eNoDynamicValues) + expr_options.SetTimeoutInMicroSeconds( + 30 * 1000 * 1000) # 30 second timeout + expr_options.SetTryAllThreads(False) + expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) + if expr_prefix: + expr_options.SetPrefix(expr_prefix) + expr_sbvalue = frame.EvaluateExpression(expr, expr_options) + if options.verbose: + print "expression:" + print expr + print "expression result:" + print expr_sbvalue + if expr_sbvalue.error.Success(): + match_value = lldb.value(expr_sbvalue) + i = 0 + match_idx = 0 + while True: + print_entry = True + match_entry = match_value[i] + i += 1 + if i > options.max_matches: + result.AppendMessage( + 'warning: the max number of matches (%u) was reached, use the --max-matches option to get more results' % + (options.max_matches)) + break + malloc_addr = match_entry.addr.sbvalue.unsigned + if malloc_addr == 0: + break + malloc_size = int(match_entry.size) + offset = int(match_entry.offset) + + if options.offset >= 0 and options.offset != offset: + print_entry = False + else: + match_addr = malloc_addr + offset + type_flags = int(match_entry.type) + #result.AppendMessage (hex(malloc_addr + offset)) + if type_flags == 64: + search_stack_old = options.search_stack + search_segments_old = options.search_segments + search_heap_old = options.search_heap + search_vm_regions = options.search_vm_regions + options.search_stack = True + options.search_segments = True + options.search_heap = True + options.search_vm_regions = False + if malloc_info_impl(lldb.debugger, result, options, [ + hex(malloc_addr + offset)]): + print_entry = False + options.search_stack = search_stack_old + options.search_segments = search_segments_old + options.search_heap = search_heap_old + options.search_vm_regions = search_vm_regions + if print_entry: + description = '%#16.16x: %s' % (match_addr, type_flags_to_description( + process, type_flags, malloc_addr, malloc_size, offset, match_addr)) + if options.show_size: + description += ' <%5u>' % (malloc_size) + if options.show_range: + description += ' [%#x - %#x)' % ( + malloc_addr, malloc_addr + malloc_size) + derefed_dynamic_value = None + dynamic_value = match_entry.addr.sbvalue.GetDynamicValue( + lldb.eDynamicCanRunTarget) + if dynamic_value.type.name == 'void *': + if options.type == 'pointer' and malloc_size == 4096: + error = lldb.SBError() + process = expr_sbvalue.GetProcess() + target = expr_sbvalue.GetTarget() + data = bytearray( + process.ReadMemory( + malloc_addr, 16, error)) + if data == '\xa1\xa1\xa1\xa1AUTORELEASE!': + ptr_size = target.addr_size + thread = process.ReadUnsignedFromMemory( + malloc_addr + 16 + ptr_size, ptr_size, error) + # 4 bytes 0xa1a1a1a1 + # 12 bytes 'AUTORELEASE!' + # ptr bytes autorelease insertion point + # ptr bytes pthread_t + # ptr bytes next colder page + # ptr bytes next hotter page + # 4 bytes this page's depth in the list + # 4 bytes high-water mark + description += ' AUTORELEASE! for pthread_t %#x' % ( + thread) + # else: + # description += 'malloc(%u)' % (malloc_size) + # else: + # description += 'malloc(%u)' % (malloc_size) + else: + derefed_dynamic_value = dynamic_value.deref + if derefed_dynamic_value: + derefed_dynamic_type = derefed_dynamic_value.type + derefed_dynamic_type_size = derefed_dynamic_type.size + derefed_dynamic_type_name = derefed_dynamic_type.name + description += ' ' + description += derefed_dynamic_type_name + if offset < derefed_dynamic_type_size: + member_list = list() + get_member_types_for_offset( + derefed_dynamic_type, offset, member_list) + if member_list: + member_path = '' + for member in member_list: + member_name = member.name + if member_name: + if member_path: + member_path += '.' + member_path += member_name + if member_path: + if options.ivar_regex_blacklist: + for ivar_regex in options.ivar_regex_blacklist: + if ivar_regex.match( + member_path): + print_entry = False + description += '.%s' % (member_path) + else: + description += '%u bytes after %s' % ( + offset - derefed_dynamic_type_size, derefed_dynamic_type_name) + else: + # strip the "*" from the end of the name since we + # were unable to dereference this + description += dynamic_value.type.name[0:-1] + if print_entry: + match_idx += 1 + result_output = '' + if description: + result_output += description + if options.print_type and derefed_dynamic_value: + result_output += ' %s' % (derefed_dynamic_value) + if options.print_object_description and dynamic_value: + desc = dynamic_value.GetObjectDescription() + if desc: + result_output += '\n%s' % (desc) + if result_output: + result.AppendMessage(result_output) + if options.memory: + cmd_result = lldb.SBCommandReturnObject() + if options.format is None: + memory_command = "memory read --force 0x%x 0x%x" % ( + malloc_addr, malloc_addr + malloc_size) + else: + memory_command = "memory read --force -f %s 0x%x 0x%x" % ( + options.format, malloc_addr, malloc_addr + malloc_size) + if options.verbose: + result.AppendMessage(memory_command) + lldb.debugger.GetCommandInterpreter().HandleCommand(memory_command, cmd_result) + result.AppendMessage(cmd_result.GetOutput()) + if options.stack_history: + dump_stack_history_entries(options, result, malloc_addr, 1) + elif options.stack: + dump_stack_history_entries(options, result, malloc_addr, 0) + return i + else: + result.AppendMessage(str(expr_sbvalue.error)) + return 0 + + +def get_ptr_refs_options(): + usage = "usage: %prog [options] [EXPR ...]" + description = '''Searches all allocations on the heap for pointer values on +darwin user space programs. Any matches that were found will dump the malloc +blocks that contain the pointers and might be able to print what kind of +objects the pointers are contained in using dynamic type information in the +program.''' + parser = optparse.OptionParser( + description=description, + prog='ptr_refs', + usage=usage) + add_common_options(parser) + return parser + + +def find_variable(debugger, command, result, dict): + usage = "usage: %prog [options] [ADDR ...]" + description = '''Searches for a local variable in all frames that contains a hex ADDR.''' + command_args = shlex.split(command) + parser = optparse.OptionParser( + description=description, + prog='find_variable', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + try: + (options, args) = parser.parse_args(command_args) + except: + return + + process = debugger.GetSelectedTarget().GetProcess() + if not process: + result.AppendMessage('error: invalid process') + return + + for arg in args: + var_addr = int(arg, 16) + print >>result, "Finding a variable with address %#x..." % (var_addr) + done = False + for thread in process: + for frame in thread: + var = find_variable_containing_address( + options.verbose, frame, var_addr) + if var: + print var + done = True + break + if done: + break + + +def ptr_refs(debugger, command, result, dict): + command_args = shlex.split(command) + parser = get_ptr_refs_options() + try: + (options, args) = parser.parse_args(command_args) + except: + return + + process = debugger.GetSelectedTarget().GetProcess() + if not process: + result.AppendMessage('error: invalid process') + return + frame = process.GetSelectedThread().GetSelectedFrame() + if not frame: + result.AppendMessage('error: invalid frame') + return + + options.type = 'pointer' + if options.format is None: + options.format = "A" # 'A' is "address" format + + if args: + # When we initialize the expression, we must define any types that + # we will need when looking at every allocation. We must also define + # a type named callback_baton_t and make an instance named "baton" + # and initialize it how ever we want to. The address of "baton" will + # be passed into our range callback. callback_baton_t must contain + # a member named "callback" whose type is "range_callback_t". This + # will be used by our zone callbacks to call the range callback for + # each malloc range. + expr_prefix = ''' +struct $malloc_match { + void *addr; + uintptr_t size; + uintptr_t offset; + uintptr_t type; +}; +''' + user_init_code_format = ''' +#define MAX_MATCHES %u +typedef struct callback_baton_t { + range_callback_t callback; + unsigned num_matches; + $malloc_match matches[MAX_MATCHES]; + void *ptr; +} callback_baton_t; +range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { + callback_baton_t *info = (callback_baton_t *)baton; + typedef void* T; + const unsigned size = sizeof(T); + T *array = (T*)ptr_addr; + for (unsigned idx = 0; ((idx + 1) * sizeof(T)) <= ptr_size; ++idx) { + if (array[idx] == info->ptr) { + if (info->num_matches < MAX_MATCHES) { + info->matches[info->num_matches].addr = (void*)ptr_addr; + info->matches[info->num_matches].size = ptr_size; + info->matches[info->num_matches].offset = idx*sizeof(T); + info->matches[info->num_matches].type = type; + ++info->num_matches; + } + } + } +}; +callback_baton_t baton = { range_callback, 0, {0}, (void *)%s }; +''' + # We must also define a snippet of code to be run that returns + # the result of the expression we run. + # Here we return NULL if our pointer was not found in any malloc blocks, + # and we return the address of the matches array so we can then access + # the matching results + user_return_code = '''if (baton.num_matches < MAX_MATCHES) + baton.matches[baton.num_matches].addr = 0; // Terminate the matches array +baton.matches''' + # Iterate through all of our pointer expressions and display the + # results + for ptr_expr in args: + user_init_code = user_init_code_format % ( + options.max_matches, ptr_expr) + expr = get_iterate_memory_expr( + options, process, user_init_code, user_return_code) + arg_str_description = 'malloc block containing pointer %s' % ptr_expr + display_match_results( + process, + result, + options, + arg_str_description, + expr, + True, + expr_prefix) + else: + result.AppendMessage('error: no pointer arguments were given') + + +def get_cstr_refs_options(): + usage = "usage: %prog [options] [CSTR ...]" + description = '''Searches all allocations on the heap for C string values on +darwin user space programs. Any matches that were found will dump the malloc +blocks that contain the C strings and might be able to print what kind of +objects the pointers are contained in using dynamic type information in the +program.''' + parser = optparse.OptionParser( + description=description, + prog='cstr_refs', + usage=usage) + add_common_options(parser) + return parser + + +def cstr_refs(debugger, command, result, dict): + command_args = shlex.split(command) + parser = get_cstr_refs_options() + try: + (options, args) = parser.parse_args(command_args) + except: + return + + process = debugger.GetSelectedTarget().GetProcess() + if not process: + result.AppendMessage('error: invalid process') + return + frame = process.GetSelectedThread().GetSelectedFrame() + if not frame: + result.AppendMessage('error: invalid frame') + return + + options.type = 'cstr' + if options.format is None: + options.format = "Y" # 'Y' is "bytes with ASCII" format + + if args: + # When we initialize the expression, we must define any types that + # we will need when looking at every allocation. We must also define + # a type named callback_baton_t and make an instance named "baton" + # and initialize it how ever we want to. The address of "baton" will + # be passed into our range callback. callback_baton_t must contain + # a member named "callback" whose type is "range_callback_t". This + # will be used by our zone callbacks to call the range callback for + # each malloc range. + expr_prefix = ''' +struct $malloc_match { + void *addr; + uintptr_t size; + uintptr_t offset; + uintptr_t type; +}; +''' + user_init_code_format = ''' +#define MAX_MATCHES %u +typedef struct callback_baton_t { + range_callback_t callback; + unsigned num_matches; + $malloc_match matches[MAX_MATCHES]; + const char *cstr; + unsigned cstr_len; +} callback_baton_t; +range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { + callback_baton_t *info = (callback_baton_t *)baton; + if (info->cstr_len < ptr_size) { + const char *begin = (const char *)ptr_addr; + const char *end = begin + ptr_size - info->cstr_len; + for (const char *s = begin; s < end; ++s) { + if ((int)memcmp(s, info->cstr, info->cstr_len) == 0) { + if (info->num_matches < MAX_MATCHES) { + info->matches[info->num_matches].addr = (void*)ptr_addr; + info->matches[info->num_matches].size = ptr_size; + info->matches[info->num_matches].offset = s - begin; + info->matches[info->num_matches].type = type; + ++info->num_matches; + } + } + } + } +}; +const char *cstr = "%s"; +callback_baton_t baton = { range_callback, 0, {0}, cstr, (unsigned)strlen(cstr) };''' + # We must also define a snippet of code to be run that returns + # the result of the expression we run. + # Here we return NULL if our pointer was not found in any malloc blocks, + # and we return the address of the matches array so we can then access + # the matching results + user_return_code = '''if (baton.num_matches < MAX_MATCHES) + baton.matches[baton.num_matches].addr = 0; // Terminate the matches array +baton.matches''' + # Iterate through all of our pointer expressions and display the + # results + for cstr in args: + user_init_code = user_init_code_format % ( + options.max_matches, cstr) + expr = get_iterate_memory_expr( + options, process, user_init_code, user_return_code) + arg_str_description = 'malloc block containing "%s"' % cstr + display_match_results( + process, + result, + options, + arg_str_description, + expr, + True, + expr_prefix) + else: + result.AppendMessage( + 'error: command takes one or more C string arguments') + + +def get_malloc_info_options(): + usage = "usage: %prog [options] [EXPR ...]" + description = '''Searches the heap a malloc block that contains the addresses +specified as one or more address expressions. Any matches that were found will +dump the malloc blocks that match or contain the specified address. The matching +blocks might be able to show what kind of objects they are using dynamic type +information in the program.''' + parser = optparse.OptionParser( + description=description, + prog='malloc_info', + usage=usage) + add_common_options(parser) + return parser + + +def malloc_info(debugger, command, result, dict): + command_args = shlex.split(command) + parser = get_malloc_info_options() + try: + (options, args) = parser.parse_args(command_args) + except: + return + malloc_info_impl(debugger, result, options, args) + + +def malloc_info_impl(debugger, result, options, args): + # We are specifically looking for something on the heap only + options.type = 'malloc_info' + + process = debugger.GetSelectedTarget().GetProcess() + if not process: + result.AppendMessage('error: invalid process') + return + frame = process.GetSelectedThread().GetSelectedFrame() + if not frame: + result.AppendMessage('error: invalid frame') + return + expr_prefix = ''' +struct $malloc_match { + void *addr; + uintptr_t size; + uintptr_t offset; + uintptr_t type; +}; +''' + + user_init_code_format = ''' +typedef struct callback_baton_t { + range_callback_t callback; + unsigned num_matches; + $malloc_match matches[2]; // Two items so they can be NULL terminated + void *ptr; +} callback_baton_t; +range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { + callback_baton_t *info = (callback_baton_t *)baton; + if (info->num_matches == 0) { + uint8_t *p = (uint8_t *)info->ptr; + uint8_t *lo = (uint8_t *)ptr_addr; + uint8_t *hi = lo + ptr_size; + if (lo <= p && p < hi) { + info->matches[info->num_matches].addr = (void*)ptr_addr; + info->matches[info->num_matches].size = ptr_size; + info->matches[info->num_matches].offset = p - lo; + info->matches[info->num_matches].type = type; + info->num_matches = 1; + } + } +}; +callback_baton_t baton = { range_callback, 0, {0}, (void *)%s }; +baton.matches[0].addr = 0; +baton.matches[1].addr = 0;''' + if args: + total_matches = 0 + for ptr_expr in args: + user_init_code = user_init_code_format % (ptr_expr) + expr = get_iterate_memory_expr( + options, process, user_init_code, 'baton.matches') + arg_str_description = 'malloc block that contains %s' % ptr_expr + total_matches += display_match_results( + process, result, options, arg_str_description, expr, True, expr_prefix) + return total_matches + else: + result.AppendMessage( + 'error: command takes one or more pointer expressions') + return 0 + + +def get_thread_stack_ranges_struct(process): + '''Create code that defines a structure that represents threads stack bounds + for all threads. It returns a static sized array initialized with all of + the tid, base, size structs for all the threads.''' + stack_dicts = list() + if process: + i = 0 + for thread in process: + min_sp = thread.frame[0].sp + max_sp = min_sp + for frame in thread.frames: + sp = frame.sp + if sp < min_sp: + min_sp = sp + if sp > max_sp: + max_sp = sp + if min_sp < max_sp: + stack_dicts.append({'tid': thread.GetThreadID( + ), 'base': min_sp, 'size': max_sp - min_sp, 'index': i}) + i += 1 + stack_dicts_len = len(stack_dicts) + if stack_dicts_len > 0: + result = ''' +#define NUM_STACKS %u +#define STACK_RED_ZONE_SIZE %u +typedef struct thread_stack_t { uint64_t tid, base, size; } thread_stack_t; +thread_stack_t stacks[NUM_STACKS];''' % (stack_dicts_len, process.target.GetStackRedZoneSize()) + for stack_dict in stack_dicts: + result += ''' +stacks[%(index)u].tid = 0x%(tid)x; +stacks[%(index)u].base = 0x%(base)x; +stacks[%(index)u].size = 0x%(size)x;''' % stack_dict + return result + else: + return '' + + +def get_sections_ranges_struct(process): + '''Create code that defines a structure that represents all segments that + can contain data for all images in "target". It returns a static sized + array initialized with all of base, size structs for all the threads.''' + target = process.target + segment_dicts = list() + for (module_idx, module) in enumerate(target.modules): + for sect_idx in range(module.GetNumSections()): + section = module.GetSectionAtIndex(sect_idx) + if not section: + break + name = section.name + if name != '__TEXT' and name != '__LINKEDIT' and name != '__PAGEZERO': + base = section.GetLoadAddress(target) + size = section.GetByteSize() + if base != lldb.LLDB_INVALID_ADDRESS and size > 0: + segment_dicts.append({'base': base, 'size': size}) + segment_dicts_len = len(segment_dicts) + if segment_dicts_len > 0: + result = ''' +#define NUM_SEGMENTS %u +typedef struct segment_range_t { uint64_t base; uint32_t size; } segment_range_t; +segment_range_t segments[NUM_SEGMENTS];''' % (segment_dicts_len,) + for (idx, segment_dict) in enumerate(segment_dicts): + segment_dict['index'] = idx + result += ''' +segments[%(index)u].base = 0x%(base)x; +segments[%(index)u].size = 0x%(size)x;''' % segment_dict + return result + else: + return '' + + +def section_ptr_refs(debugger, command, result, dict): + command_args = shlex.split(command) + usage = "usage: %prog [options] [EXPR ...]" + description = '''Searches section contents for pointer values in darwin user space programs.''' + parser = optparse.OptionParser( + description=description, + prog='section_ptr_refs', + usage=usage) + add_common_options(parser) + parser.add_option( + '--section', + action='append', + type='string', + dest='section_names', + help='section name to search', + default=list()) + try: + (options, args) = parser.parse_args(command_args) + except: + return + + options.type = 'pointer' + + sections = list() + section_modules = list() + if not options.section_names: + result.AppendMessage( + 'error: at least one section must be specified with the --section option') + return + + target = debugger.GetSelectedTarget() + for module in target.modules: + for section_name in options.section_names: + section = module.section[section_name] + if section: + sections.append(section) + section_modules.append(module) + if sections: + dylid_load_err = load_dylib() + if dylid_load_err: + result.AppendMessage(dylid_load_err) + return + frame = target.GetProcess().GetSelectedThread().GetSelectedFrame() + for expr_str in args: + for (idx, section) in enumerate(sections): + expr = 'find_pointer_in_memory(0x%xllu, %ullu, (void *)%s)' % ( + section.addr.load_addr, section.size, expr_str) + arg_str_description = 'section %s.%s containing "%s"' % ( + section_modules[idx].file.fullpath, section.name, expr_str) + num_matches = display_match_results( + target.GetProcess(), result, options, arg_str_description, expr, False) + if num_matches: + if num_matches < options.max_matches: + options.max_matches = options.max_matches - num_matches + else: + options.max_matches = 0 + if options.max_matches == 0: + return + else: + result.AppendMessage( + 'error: no sections were found that match any of %s' % + (', '.join( + options.section_names))) + + +def get_objc_refs_options(): + usage = "usage: %prog [options] [CLASS ...]" + description = '''Searches all allocations on the heap for instances of +objective C classes, or any classes that inherit from the specified classes +in darwin user space programs. Any matches that were found will dump the malloc +blocks that contain the C strings and might be able to print what kind of +objects the pointers are contained in using dynamic type information in the +program.''' + parser = optparse.OptionParser( + description=description, + prog='objc_refs', + usage=usage) + add_common_options(parser) + return parser + + +def objc_refs(debugger, command, result, dict): + command_args = shlex.split(command) + parser = get_objc_refs_options() + try: + (options, args) = parser.parse_args(command_args) + except: + return + + process = debugger.GetSelectedTarget().GetProcess() + if not process: + result.AppendMessage('error: invalid process') + return + frame = process.GetSelectedThread().GetSelectedFrame() + if not frame: + result.AppendMessage('error: invalid frame') + return + + options.type = 'isa' + if options.format is None: + options.format = "A" # 'A' is "address" format + + expr_options = lldb.SBExpressionOptions() + expr_options.SetIgnoreBreakpoints(True) + expr_options.SetTimeoutInMicroSeconds( + 3 * 1000 * 1000) # 3 second infinite timeout + expr_options.SetTryAllThreads(True) + expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) + num_objc_classes_value = frame.EvaluateExpression( + "(int)objc_getClassList((void *)0, (int)0)", expr_options) + if not num_objc_classes_value.error.Success(): + result.AppendMessage('error: %s' % + num_objc_classes_value.error.GetCString()) + return + + num_objc_classes = num_objc_classes_value.GetValueAsUnsigned() + if num_objc_classes == 0: + result.AppendMessage('error: no objective C classes in program') + return + + if args: + # When we initialize the expression, we must define any types that + # we will need when looking at every allocation. We must also define + # a type named callback_baton_t and make an instance named "baton" + # and initialize it how ever we want to. The address of "baton" will + # be passed into our range callback. callback_baton_t must contain + # a member named "callback" whose type is "range_callback_t". This + # will be used by our zone callbacks to call the range callback for + # each malloc range. + expr_prefix = ''' +struct $malloc_match { + void *addr; + uintptr_t size; + uintptr_t offset; + uintptr_t type; +}; +''' + + user_init_code_format = ''' +#define MAX_MATCHES %u +typedef int (*compare_callback_t)(const void *a, const void *b); +typedef struct callback_baton_t { + range_callback_t callback; + compare_callback_t compare_callback; + unsigned num_matches; + $malloc_match matches[MAX_MATCHES]; + void *isa; + Class classes[%u]; +} callback_baton_t; +compare_callback_t compare_callback = [](const void *a, const void *b) -> int { + Class a_ptr = *(Class *)a; + Class b_ptr = *(Class *)b; + if (a_ptr < b_ptr) return -1; + if (a_ptr > b_ptr) return +1; + return 0; +}; +typedef Class (*class_getSuperclass_type)(void *isa); +range_callback_t range_callback = [](task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size) -> void { + class_getSuperclass_type class_getSuperclass_impl = (class_getSuperclass_type)class_getSuperclass; + callback_baton_t *info = (callback_baton_t *)baton; + if (sizeof(Class) <= ptr_size) { + Class *curr_class_ptr = (Class *)ptr_addr; + Class *matching_class_ptr = (Class *)bsearch (curr_class_ptr, + (const void *)info->classes, + sizeof(info->classes)/sizeof(Class), + sizeof(Class), + info->compare_callback); + if (matching_class_ptr) { + bool match = false; + if (info->isa) { + Class isa = *curr_class_ptr; + if (info->isa == isa) + match = true; + else { // if (info->objc.match_superclasses) { + Class super = class_getSuperclass_impl(isa); + while (super) { + if (super == info->isa) { + match = true; + break; + } + super = class_getSuperclass_impl(super); + } + } + } + else + match = true; + if (match) { + if (info->num_matches < MAX_MATCHES) { + info->matches[info->num_matches].addr = (void*)ptr_addr; + info->matches[info->num_matches].size = ptr_size; + info->matches[info->num_matches].offset = 0; + info->matches[info->num_matches].type = type; + ++info->num_matches; + } + } + } + } +}; +callback_baton_t baton = { range_callback, compare_callback, 0, {0}, (void *)0x%x, {0} }; +int nc = (int)objc_getClassList(baton.classes, sizeof(baton.classes)/sizeof(Class)); +(void)qsort (baton.classes, sizeof(baton.classes)/sizeof(Class), sizeof(Class), compare_callback);''' + # We must also define a snippet of code to be run that returns + # the result of the expression we run. + # Here we return NULL if our pointer was not found in any malloc blocks, + # and we return the address of the matches array so we can then access + # the matching results + user_return_code = '''if (baton.num_matches < MAX_MATCHES) + baton.matches[baton.num_matches].addr = 0; // Terminate the matches array + baton.matches''' + # Iterate through all of our ObjC class name arguments + for class_name in args: + addr_expr_str = "(void *)[%s class]" % class_name + expr_options = lldb.SBExpressionOptions() + expr_options.SetIgnoreBreakpoints(True) + expr_options.SetTimeoutInMicroSeconds( + 1 * 1000 * 1000) # 1 second timeout + expr_options.SetTryAllThreads(True) + expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) + expr_sbvalue = frame.EvaluateExpression( + addr_expr_str, expr_options) + if expr_sbvalue.error.Success(): + isa = expr_sbvalue.unsigned + if isa: + options.type = 'isa' + result.AppendMessage( + 'Searching for all instances of classes or subclasses of "%s" (isa=0x%x)' % + (class_name, isa)) + user_init_code = user_init_code_format % ( + options.max_matches, num_objc_classes, isa) + expr = get_iterate_memory_expr( + options, process, user_init_code, user_return_code) + arg_str_description = 'objective C classes with isa 0x%x' % isa + display_match_results( + process, + result, + options, + arg_str_description, + expr, + True, + expr_prefix) + else: + result.AppendMessage( + 'error: Can\'t find isa for an ObjC class named "%s"' % + (class_name)) + else: + result.AppendMessage( + 'error: expression error for "%s": %s' % + (addr_expr_str, expr_sbvalue.error)) + else: + result.AppendMessage( + 'error: command takes one or more C string arguments') + +if __name__ == '__main__': + lldb.debugger = lldb.SBDebugger.Create() + +# Make the options so we can generate the help text for the new LLDB +# command line command prior to registering it with LLDB below. This way +# if clients in LLDB type "help malloc_info", they will see the exact same +# output as typing "malloc_info --help". +ptr_refs.__doc__ = get_ptr_refs_options().format_help() +cstr_refs.__doc__ = get_cstr_refs_options().format_help() +malloc_info.__doc__ = get_malloc_info_options().format_help() +objc_refs.__doc__ = get_objc_refs_options().format_help() +lldb.debugger.HandleCommand( + 'command script add -f %s.ptr_refs ptr_refs' % + __name__) +lldb.debugger.HandleCommand( + 'command script add -f %s.cstr_refs cstr_refs' % + __name__) +lldb.debugger.HandleCommand( + 'command script add -f %s.malloc_info malloc_info' % + __name__) +lldb.debugger.HandleCommand( + 'command script add -f %s.find_variable find_variable' % + __name__) +# lldb.debugger.HandleCommand('command script add -f %s.heap heap' % package_name) +# lldb.debugger.HandleCommand('command script add -f %s.section_ptr_refs section_ptr_refs' % package_name) +# lldb.debugger.HandleCommand('command script add -f %s.stack_ptr_refs stack_ptr_refs' % package_name) +lldb.debugger.HandleCommand( + 'command script add -f %s.objc_refs objc_refs' % + __name__) +print '"malloc_info", "ptr_refs", "cstr_refs", "find_variable", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.' diff --git a/examples/darwin/heap_find/heap/Makefile b/examples/darwin/heap_find/heap/Makefile new file mode 100644 index 000000000..0e33dc9f8 --- /dev/null +++ b/examples/darwin/heap_find/heap/Makefile @@ -0,0 +1,33 @@ +#---------------------------------------------------------------------- +# Fill in the source files to build +#---------------------------------------------------------------------- +# Uncomment line below for debugging shell commands +# SHELL = /bin/sh -x + +#---------------------------------------------------------------------- +# Change any build/tool options needed +#---------------------------------------------------------------------- +ARCH ?= x86_64 +CFLAGS ?=-arch $(ARCH) -gdwarf-2 -O0 +CXX ?= $(shell xcrun -find clang++) +EXE ?= libheap.dylib +DSYM ?= $(EXE).dSYM + +#---------------------------------------------------------------------- +# Compile the executable from all the objects (default rule) with no +# dsym file. +#---------------------------------------------------------------------- +$(EXE) : heap_find.cpp + $(CXX) $(CFLAGS) -install_name "@executable_path/libheap.dylib" -dynamiclib -lobjc heap_find.cpp -o "$(EXE)" + +#---------------------------------------------------------------------- +# 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. +#---------------------------------------------------------------------- +.PHONY: clean +all: $(EXE) +clean: + rm -rf "$(EXE)" "$(DSYM)" + + + diff --git a/examples/darwin/heap_find/heap/heap_find.cpp b/examples/darwin/heap_find/heap/heap_find.cpp new file mode 100644 index 000000000..3567e559a --- /dev/null +++ b/examples/darwin/heap_find/heap/heap_find.cpp @@ -0,0 +1,911 @@ +//===-- heap_find.c ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file compiles into a dylib and can be used on darwin to find data that +// is contained in active malloc blocks. To use this make the project, then +// load the shared library in a debug session while you are stopped: +// +// (lldb) process load /path/to/libheap.dylib +// +// Now you can use the "find_pointer_in_heap" and "find_cstring_in_heap" +// functions in the expression parser. +// +// This will grep everything in all active allocation blocks and print and +// malloc blocks that contain the pointer 0x112233000000: +// +// (lldb) expression find_pointer_in_heap (0x112233000000) +// +// This will grep everything in all active allocation blocks and print and +// malloc blocks that contain the C string "hello" (as a substring, no +// NULL termination included): +// +// (lldb) expression find_cstring_in_heap ("hello") +// +// The results will be printed to the STDOUT of the inferior program. The +// return value of the "find_pointer_in_heap" function is the number of +// pointer references that were found. A quick example shows +// +// (lldb) expr find_pointer_in_heap(0x0000000104000410) +// (uint32_t) $5 = 0x00000002 +// 0x104000740: 0x0000000104000410 found in malloc block 0x104000730 + 16 +// (malloc_size = 48) +// 0x100820060: 0x0000000104000410 found in malloc block 0x100820000 + 96 +// (malloc_size = 4096) +// +// From the above output we see that 0x104000410 was found in the malloc block +// at 0x104000730 and 0x100820000. If we want to see what these blocks are, we +// can display the memory for this block using the "address" ("A" for short) +// format. The address format shows pointers, and if those pointers point to +// objects that have symbols or know data contents, it will display information +// about the pointers: +// +// (lldb) memory read --format address --count 1 0x104000730 +// 0x104000730: 0x0000000100002460 (void *)0x0000000100002488: MyString +// +// We can see that the first block is a "MyString" object that contains our +// pointer value at offset 16. +// +// Looking at the next pointers, are a bit more tricky: +// (lldb) memory read -fA 0x100820000 -c1 +// 0x100820000: 0x4f545541a1a1a1a1 +// (lldb) memory read 0x100820000 +// 0x100820000: a1 a1 a1 a1 41 55 54 4f 52 45 4c 45 41 53 45 21 ....AUTORELEASE! +// 0x100820010: 78 00 82 00 01 00 00 00 60 f9 e8 75 ff 7f 00 00 x.......`..u.... +// +// This is an objective C auto release pool object that contains our pointer. +// C++ classes will show up if they are virtual as something like: +// (lldb) memory read --format address --count 1 0x104008000 +// 0x104008000: 0x109008000 vtable for lldb_private::Process +// +// This is a clue that the 0x104008000 is a "lldb_private::Process *". +//===----------------------------------------------------------------------===// +// C includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// C++ includes +#include + +//---------------------------------------------------------------------- +// Redefine private types from "/usr/local/include/stack_logging.h" +//---------------------------------------------------------------------- +typedef struct { + uint32_t type_flags; + uint64_t stack_identifier; + uint64_t argument; + mach_vm_address_t address; +} mach_stack_logging_record_t; + +//---------------------------------------------------------------------- +// Redefine private defines from "/usr/local/include/stack_logging.h" +//---------------------------------------------------------------------- +#define stack_logging_type_free 0 +#define stack_logging_type_generic 1 +#define stack_logging_type_alloc 2 +#define stack_logging_type_dealloc 4 +// This bit is made up by this code +#define stack_logging_type_vm_region 8 + +//---------------------------------------------------------------------- +// Redefine private function prototypes from +// "/usr/local/include/stack_logging.h" +//---------------------------------------------------------------------- +extern "C" kern_return_t __mach_stack_logging_set_file_path(task_t task, + char *file_path); + +extern "C" kern_return_t +__mach_stack_logging_get_frames(task_t task, mach_vm_address_t address, + mach_vm_address_t *stack_frames_buffer, + uint32_t max_stack_frames, uint32_t *count); + +extern "C" kern_return_t __mach_stack_logging_enumerate_records( + task_t task, mach_vm_address_t address, + void enumerator(mach_stack_logging_record_t, void *), void *context); + +extern "C" kern_return_t __mach_stack_logging_frames_for_uniqued_stack( + task_t task, uint64_t stack_identifier, + mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, + uint32_t *count); + +extern "C" void *gdb_class_getClass(void *objc_class); + +static void range_info_callback(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size); + +//---------------------------------------------------------------------- +// Redefine private global variables prototypes from +// "/usr/local/include/stack_logging.h" +//---------------------------------------------------------------------- + +extern "C" int stack_logging_enable_logging; + +//---------------------------------------------------------------------- +// Local defines +//---------------------------------------------------------------------- +#define MAX_FRAMES 1024 + +//---------------------------------------------------------------------- +// Local Typedefs and Types +//---------------------------------------------------------------------- +typedef void range_callback_t(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size); +typedef void zone_callback_t(void *info, const malloc_zone_t *zone); +typedef int (*comare_function_t)(const void *, const void *); +struct range_callback_info_t { + zone_callback_t *zone_callback; + range_callback_t *range_callback; + void *baton; + int check_vm_regions; +}; + +enum data_type_t { + eDataTypeAddress, + eDataTypeContainsData, + eDataTypeObjC, + eDataTypeHeapInfo +}; + +struct aligned_data_t { + const uint8_t *buffer; + uint32_t size; + uint32_t align; +}; + +struct objc_data_t { + void *match_isa; // Set to NULL for all objective C objects + bool match_superclasses; +}; + +struct range_contains_data_callback_info_t { + data_type_t type; + const void *lookup_addr; + union { + uintptr_t addr; + aligned_data_t data; + objc_data_t objc; + }; + uint32_t match_count; + bool done; + bool unique; +}; + +struct malloc_match { + void *addr; + intptr_t size; + intptr_t offset; + uintptr_t type; +}; + +struct malloc_stack_entry { + const void *address; + uint64_t argument; + uint32_t type_flags; + uint32_t num_frames; + mach_vm_address_t frames[MAX_FRAMES]; +}; + +struct malloc_block_contents { + union { + Class isa; + void *pointers[2]; + }; +}; + +static int compare_void_ptr(const void *a, const void *b) { + Class a_ptr = *(Class *)a; + Class b_ptr = *(Class *)b; + if (a_ptr < b_ptr) + return -1; + if (a_ptr > b_ptr) + return +1; + return 0; +} + +class MatchResults { + enum { k_max_entries = 8 * 1024 }; + +public: + MatchResults() : m_size(0) {} + + void clear() { + m_size = 0; + bzero(&m_entries, sizeof(m_entries)); + } + + bool empty() const { return m_size == 0; } + + void push_back(const malloc_match &m, bool unique = false) { + if (unique) { + // Don't add the entry if there is already a match for this address + for (uint32_t i = 0; i < m_size; ++i) { + if (((uint8_t *)m_entries[i].addr + m_entries[i].offset) == + ((uint8_t *)m.addr + m.offset)) + return; // Duplicate entry + } + } + if (m_size < k_max_entries - 1) { + m_entries[m_size] = m; + m_size++; + } + } + + malloc_match *data() { + // If empty, return NULL + if (empty()) + return NULL; + // In not empty, terminate and return the result + malloc_match terminator_entry = {NULL, 0, 0, 0}; + // We always leave room for an empty entry at the end + m_entries[m_size] = terminator_entry; + return m_entries; + } + +protected: + malloc_match m_entries[k_max_entries]; + uint32_t m_size; +}; + +class MallocStackLoggingEntries { + enum { k_max_entries = 128 }; + +public: + MallocStackLoggingEntries() : m_size(0) {} + + void clear() { m_size = 0; } + + bool empty() const { return m_size == 0; } + + malloc_stack_entry *next() { + if (m_size < k_max_entries - 1) { + malloc_stack_entry *result = m_entries + m_size; + ++m_size; + return result; + } + return NULL; // Out of entries... + } + + malloc_stack_entry *data() { + // If empty, return NULL + if (empty()) + return NULL; + // In not empty, terminate and return the result + m_entries[m_size].address = NULL; + m_entries[m_size].argument = 0; + m_entries[m_size].type_flags = 0; + m_entries[m_size].num_frames = 0; + return m_entries; + } + +protected: + malloc_stack_entry m_entries[k_max_entries]; + uint32_t m_size; +}; + +//---------------------------------------------------------------------- +// A safe way to allocate memory and keep it from interfering with the +// malloc enumerators. +//---------------------------------------------------------------------- +void *safe_malloc(size_t n_bytes) { + if (n_bytes > 0) { + const int k_page_size = getpagesize(); + const mach_vm_size_t vm_size = + ((n_bytes + k_page_size - 1) / k_page_size) * k_page_size; + vm_address_t address = 0; + kern_return_t kerr = vm_allocate(mach_task_self(), &address, vm_size, true); + if (kerr == KERN_SUCCESS) + return (void *)address; + } + return NULL; +} + +//---------------------------------------------------------------------- +// ObjCClasses +//---------------------------------------------------------------------- +class ObjCClasses { +public: + ObjCClasses() : m_objc_class_ptrs(NULL), m_size(0) {} + + bool Update() { + // TODO: find out if class list has changed and update if needed + if (m_objc_class_ptrs == NULL) { + m_size = objc_getClassList(NULL, 0); + if (m_size > 0) { + // Allocate the class pointers + m_objc_class_ptrs = (Class *)safe_malloc(m_size * sizeof(Class)); + m_size = objc_getClassList(m_objc_class_ptrs, m_size); + // Sort Class pointers for quick lookup + ::qsort(m_objc_class_ptrs, m_size, sizeof(Class), compare_void_ptr); + } else + return false; + } + return true; + } + + uint32_t FindClassIndex(Class isa) { + Class *matching_class = (Class *)bsearch(&isa, m_objc_class_ptrs, m_size, + sizeof(Class), compare_void_ptr); + if (matching_class) { + uint32_t idx = matching_class - m_objc_class_ptrs; + return idx; + } + return UINT32_MAX; + } + + Class GetClassAtIndex(uint32_t idx) const { + if (idx < m_size) + return m_objc_class_ptrs[idx]; + return NULL; + } + uint32_t GetSize() const { return m_size; } + +private: + Class *m_objc_class_ptrs; + uint32_t m_size; +}; + +//---------------------------------------------------------------------- +// Local global variables +//---------------------------------------------------------------------- +MatchResults g_matches; +MallocStackLoggingEntries g_malloc_stack_history; +ObjCClasses g_objc_classes; + +//---------------------------------------------------------------------- +// ObjCClassInfo +//---------------------------------------------------------------------- + +enum HeapInfoSortType { eSortTypeNone, eSortTypeBytes, eSortTypeCount }; + +class ObjCClassInfo { +public: + ObjCClassInfo() : m_entries(NULL), m_size(0), m_sort_type(eSortTypeNone) {} + + void Update(const ObjCClasses &objc_classes) { + m_size = objc_classes.GetSize(); + m_entries = (Entry *)safe_malloc(m_size * sizeof(Entry)); + m_sort_type = eSortTypeNone; + Reset(); + } + + bool AddInstance(uint32_t idx, uint64_t ptr_size) { + if (m_size == 0) + Update(g_objc_classes); + // Update the totals for the classes + if (idx < m_size) { + m_entries[idx].bytes += ptr_size; + ++m_entries[idx].count; + return true; + } + return false; + } + + void Reset() { + m_sort_type = eSortTypeNone; + for (uint32_t i = 0; i < m_size; ++i) { + // In case we sort the entries after gathering the data, we will + // want to know the index into the m_objc_class_ptrs[] array. + m_entries[i].idx = i; + m_entries[i].bytes = 0; + m_entries[i].count = 0; + } + } + void SortByTotalBytes(const ObjCClasses &objc_classes, bool print) { + if (m_sort_type != eSortTypeBytes && m_size > 0) { + ::qsort(m_entries, m_size, sizeof(Entry), + (comare_function_t)compare_bytes); + m_sort_type = eSortTypeBytes; + } + if (print && m_size > 0) { + puts("Objective C objects by total bytes:"); + puts("Total Bytes Class Name"); + puts("----------- " + "-----------------------------------------------------------------"); + for (uint32_t i = 0; i < m_size && m_entries[i].bytes > 0; ++i) { + printf("%11llu %s\n", m_entries[i].bytes, + class_getName(objc_classes.GetClassAtIndex(m_entries[i].idx))); + } + } + } + void SortByTotalCount(const ObjCClasses &objc_classes, bool print) { + if (m_sort_type != eSortTypeCount && m_size > 0) { + ::qsort(m_entries, m_size, sizeof(Entry), + (comare_function_t)compare_count); + m_sort_type = eSortTypeCount; + } + if (print && m_size > 0) { + puts("Objective C objects by total count:"); + puts("Count Class Name"); + puts("-------- " + "-----------------------------------------------------------------"); + for (uint32_t i = 0; i < m_size && m_entries[i].count > 0; ++i) { + printf("%8u %s\n", m_entries[i].count, + class_getName(objc_classes.GetClassAtIndex(m_entries[i].idx))); + } + } + } + +private: + struct Entry { + uint32_t idx; // Index into the m_objc_class_ptrs[] array + uint32_t count; // Number of object instances that were found + uint64_t bytes; // Total number of bytes for each objc class + }; + + static int compare_bytes(const Entry *a, const Entry *b) { + // Reverse the comparison to most bytes entries end up at top of list + if (a->bytes > b->bytes) + return -1; + if (a->bytes < b->bytes) + return +1; + return 0; + } + + static int compare_count(const Entry *a, const Entry *b) { + // Reverse the comparison to most count entries end up at top of list + if (a->count > b->count) + return -1; + if (a->count < b->count) + return +1; + return 0; + } + + Entry *m_entries; + uint32_t m_size; + HeapInfoSortType m_sort_type; +}; + +ObjCClassInfo g_objc_class_snapshot; + +//---------------------------------------------------------------------- +// task_peek +// +// Reads memory from this tasks address space. This callback is needed +// by the code that iterates through all of the malloc blocks to read +// the memory in this process. +//---------------------------------------------------------------------- +static kern_return_t task_peek(task_t task, vm_address_t remote_address, + vm_size_t size, void **local_memory) { + *local_memory = (void *)remote_address; + return KERN_SUCCESS; +} + +static const void foreach_zone_in_this_process(range_callback_info_t *info) { + if (info == NULL || info->zone_callback == NULL) + return; + + vm_address_t *zones = NULL; + unsigned int num_zones = 0; + + kern_return_t err = malloc_get_all_zones(0, task_peek, &zones, &num_zones); + if (KERN_SUCCESS == err) { + for (unsigned int i = 0; i < num_zones; ++i) { + info->zone_callback(info, (const malloc_zone_t *)zones[i]); + } + } + + if (info->check_vm_regions) { +#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 task = mach_task_self(); + mach_vm_address_t vm_region_base_addr; + mach_vm_size_t vm_region_size; + natural_t vm_region_depth; + RegionInfo vm_region_info; + + ((range_contains_data_callback_info_t *)info->baton)->unique = true; + + for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; + vm_region_base_addr += vm_region_size) { + mach_msg_type_number_t vm_region_info_size = kRegionInfoSize; + const kern_return_t err = mach_vm_region_recurse( + task, &vm_region_base_addr, &vm_region_size, &vm_region_depth, + (vm_region_recurse_info_t)&vm_region_info, &vm_region_info_size); + if (err) + break; + // Check all read + write regions. This will cover the thread stacks + // and any regions of memory that aren't covered by the heap + if (vm_region_info.protection & VM_PROT_WRITE && + vm_region_info.protection & VM_PROT_READ) { + // printf ("checking vm_region: [0x%16.16llx - 0x%16.16llx)\n", + // (uint64_t)vm_region_base_addr, (uint64_t)vm_region_base_addr + + // vm_region_size); + range_info_callback(task, info->baton, stack_logging_type_vm_region, + vm_region_base_addr, vm_region_size); + } + } + } +} + +//---------------------------------------------------------------------- +// dump_malloc_block_callback +// +// A simple callback that will dump each malloc block and all available +// info from the enumeration callback perspective. +//---------------------------------------------------------------------- +static void dump_malloc_block_callback(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size) { + printf("task = 0x%4.4x: baton = %p, type = %u, ptr_addr = 0x%llx + 0x%llu\n", + task, baton, type, ptr_addr, ptr_size); +} + +static void ranges_callback(task_t task, void *baton, unsigned type, + vm_range_t *ptrs, unsigned count) { + range_callback_info_t *info = (range_callback_info_t *)baton; + while (count--) { + info->range_callback(task, info->baton, type, ptrs->address, ptrs->size); + ptrs++; + } +} + +static void enumerate_range_in_zone(void *baton, const malloc_zone_t *zone) { + range_callback_info_t *info = (range_callback_info_t *)baton; + + if (zone && zone->introspect) + zone->introspect->enumerator( + mach_task_self(), info, MALLOC_PTR_IN_USE_RANGE_TYPE, + (vm_address_t)zone, task_peek, ranges_callback); +} + +static void range_info_callback(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size) { + const uint64_t end_addr = ptr_addr + ptr_size; + + range_contains_data_callback_info_t *info = + (range_contains_data_callback_info_t *)baton; + switch (info->type) { + case eDataTypeAddress: + // Check if the current malloc block contains an address specified by + // "info->addr" + if (ptr_addr <= info->addr && info->addr < end_addr) { + ++info->match_count; + malloc_match match = {(void *)ptr_addr, ptr_size, info->addr - ptr_addr, + type}; + g_matches.push_back(match, info->unique); + } + break; + + case eDataTypeContainsData: + // Check if the current malloc block contains data specified in "info->data" + { + const uint32_t size = info->data.size; + if (size < ptr_size) // Make sure this block can contain this data + { + uint8_t *ptr_data = NULL; + if (task_peek(task, ptr_addr, ptr_size, (void **)&ptr_data) == + KERN_SUCCESS) { + const void *buffer = info->data.buffer; + assert(ptr_data); + const uint32_t align = info->data.align; + for (uint64_t addr = ptr_addr; + addr < end_addr && ((end_addr - addr) >= size); + addr += align, ptr_data += align) { + if (memcmp(buffer, ptr_data, size) == 0) { + ++info->match_count; + malloc_match match = {(void *)ptr_addr, ptr_size, addr - ptr_addr, + type}; + g_matches.push_back(match, info->unique); + } + } + } else { + printf("0x%llx: error: couldn't read %llu bytes\n", ptr_addr, + ptr_size); + } + } + } + break; + + case eDataTypeObjC: + // Check if the current malloc block contains an objective C object + // of any sort where the first pointer in the object is an OBJC class + // pointer (an isa) + { + malloc_block_contents *block_contents = NULL; + if (task_peek(task, ptr_addr, sizeof(void *), (void **)&block_contents) == + KERN_SUCCESS) { + // We assume that g_objc_classes is up to date + // that the class list was verified to have some classes in it + // before calling this function + const uint32_t objc_class_idx = + g_objc_classes.FindClassIndex(block_contents->isa); + if (objc_class_idx != UINT32_MAX) { + bool match = false; + if (info->objc.match_isa == 0) { + // Match any objective C object + match = true; + } else { + // Only match exact isa values in the current class or + // optionally in the super classes + if (info->objc.match_isa == block_contents->isa) + match = true; + else if (info->objc.match_superclasses) { + Class super = class_getSuperclass(block_contents->isa); + while (super) { + match = super == info->objc.match_isa; + if (match) + break; + super = class_getSuperclass(super); + } + } + } + if (match) { + // printf (" success\n"); + ++info->match_count; + malloc_match match = {(void *)ptr_addr, ptr_size, 0, type}; + g_matches.push_back(match, info->unique); + } else { + // printf (" error: wrong class: %s\n", dl_info.dli_sname); + } + } else { + // printf ("\terror: symbol not objc class: %s\n", dl_info.dli_sname); + return; + } + } + } + break; + + case eDataTypeHeapInfo: + // Check if the current malloc block contains an objective C object + // of any sort where the first pointer in the object is an OBJC class + // pointer (an isa) + { + malloc_block_contents *block_contents = NULL; + if (task_peek(task, ptr_addr, sizeof(void *), (void **)&block_contents) == + KERN_SUCCESS) { + // We assume that g_objc_classes is up to date + // that the class list was verified to have some classes in it + // before calling this function + const uint32_t objc_class_idx = + g_objc_classes.FindClassIndex(block_contents->isa); + if (objc_class_idx != UINT32_MAX) { + // This is an objective C object + g_objc_class_snapshot.AddInstance(objc_class_idx, ptr_size); + } else { + // Classify other heap info + } + } + } + break; + } +} + +static void +get_stack_for_address_enumerator(mach_stack_logging_record_t stack_record, + void *task_ptr) { + malloc_stack_entry *stack_entry = g_malloc_stack_history.next(); + if (stack_entry) { + stack_entry->address = (void *)stack_record.address; + stack_entry->type_flags = stack_record.type_flags; + stack_entry->argument = stack_record.argument; + stack_entry->num_frames = 0; + stack_entry->frames[0] = 0; + kern_return_t err = __mach_stack_logging_frames_for_uniqued_stack( + *(task_t *)task_ptr, stack_record.stack_identifier, stack_entry->frames, + MAX_FRAMES, &stack_entry->num_frames); + // Terminate the frames with zero if there is room + if (stack_entry->num_frames < MAX_FRAMES) + stack_entry->frames[stack_entry->num_frames] = 0; + } +} + +malloc_stack_entry *get_stack_history_for_address(const void *addr, + int history) { + if (!stack_logging_enable_logging) + return NULL; + g_malloc_stack_history.clear(); + kern_return_t err; + task_t task = mach_task_self(); + if (history) { + err = __mach_stack_logging_enumerate_records( + task, (mach_vm_address_t)addr, get_stack_for_address_enumerator, &task); + } else { + malloc_stack_entry *stack_entry = g_malloc_stack_history.next(); + if (stack_entry) { + stack_entry->address = addr; + stack_entry->type_flags = stack_logging_type_alloc; + stack_entry->argument = 0; + stack_entry->num_frames = 0; + stack_entry->frames[0] = 0; + err = __mach_stack_logging_get_frames(task, (mach_vm_address_t)addr, + stack_entry->frames, MAX_FRAMES, + &stack_entry->num_frames); + if (err == 0 && stack_entry->num_frames > 0) { + // Terminate the frames with zero if there is room + if (stack_entry->num_frames < MAX_FRAMES) + stack_entry->frames[stack_entry->num_frames] = 0; + } else { + g_malloc_stack_history.clear(); + } + } + } + // Return data if there is any + return g_malloc_stack_history.data(); +} + +//---------------------------------------------------------------------- +// find_pointer_in_heap +// +// Finds a pointer value inside one or more currently valid malloc +// blocks. +//---------------------------------------------------------------------- +malloc_match *find_pointer_in_heap(const void *addr, int check_vm_regions) { + g_matches.clear(); + // Setup "info" to look for a malloc block that contains data + // that is the pointer + if (addr) { + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeContainsData; // Check each block for data + data_info.data.buffer = + (uint8_t *)&addr; // What data? The pointer value passed in + data_info.data.size = + sizeof(addr); // How many bytes? The byte size of a pointer + data_info.data.align = sizeof(addr); // Align to a pointer byte size + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + } + return g_matches.data(); +} + +//---------------------------------------------------------------------- +// find_pointer_in_memory +// +// Finds a pointer value inside one or more currently valid malloc +// blocks. +//---------------------------------------------------------------------- +malloc_match *find_pointer_in_memory(uint64_t memory_addr, uint64_t memory_size, + const void *addr) { + g_matches.clear(); + // Setup "info" to look for a malloc block that contains data + // that is the pointer + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeContainsData; // Check each block for data + data_info.data.buffer = + (uint8_t *)&addr; // What data? The pointer value passed in + data_info.data.size = + sizeof(addr); // How many bytes? The byte size of a pointer + data_info.data.align = sizeof(addr); // Align to a pointer byte size + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_info_callback(mach_task_self(), &data_info, stack_logging_type_generic, + memory_addr, memory_size); + return g_matches.data(); +} + +//---------------------------------------------------------------------- +// find_objc_objects_in_memory +// +// Find all instances of ObjC classes 'c', or all ObjC classes if 'c' is +// NULL. If 'c' is non NULL, then also check objects to see if they +// inherit from 'c' +//---------------------------------------------------------------------- +malloc_match *find_objc_objects_in_memory(void *isa, int check_vm_regions) { + g_matches.clear(); + if (g_objc_classes.Update()) { + // Setup "info" to look for a malloc block that contains data + // that is the pointer + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeObjC; // Check each block for data + data_info.objc.match_isa = isa; + data_info.objc.match_superclasses = true; + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + } + return g_matches.data(); +} + +//---------------------------------------------------------------------- +// get_heap_info +// +// Gather information for all allocations on the heap and report +// statistics. +//---------------------------------------------------------------------- + +void get_heap_info(int sort_type) { + if (g_objc_classes.Update()) { + // Reset all stats + g_objc_class_snapshot.Reset(); + // Setup "info" to look for a malloc block that contains data + // that is the pointer + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeHeapInfo; // Check each block for data + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + const int check_vm_regions = false; + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + + // Sort and print byte total bytes + switch (sort_type) { + case eSortTypeNone: + default: + case eSortTypeBytes: + g_objc_class_snapshot.SortByTotalBytes(g_objc_classes, true); + break; + + case eSortTypeCount: + g_objc_class_snapshot.SortByTotalCount(g_objc_classes, true); + break; + } + } else { + printf("error: no objective C classes\n"); + } +} + +//---------------------------------------------------------------------- +// find_cstring_in_heap +// +// Finds a C string inside one or more currently valid malloc blocks. +//---------------------------------------------------------------------- +malloc_match *find_cstring_in_heap(const char *s, int check_vm_regions) { + g_matches.clear(); + if (s == NULL || s[0] == '\0') { + printf("error: invalid argument (empty cstring)\n"); + return NULL; + } + // Setup "info" to look for a malloc block that contains data + // that is the C string passed in aligned on a 1 byte boundary + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeContainsData; // Check each block for data + data_info.data.buffer = (uint8_t *)s; // What data? The C string passed in + data_info.data.size = strlen(s); // How many bytes? The length of the C string + data_info.data.align = + 1; // Data doesn't need to be aligned, so set the alignment to 1 + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + return g_matches.data(); +} + +//---------------------------------------------------------------------- +// find_block_for_address +// +// Find the malloc block that whose address range contains "addr". +//---------------------------------------------------------------------- +malloc_match *find_block_for_address(const void *addr, int check_vm_regions) { + g_matches.clear(); + // Setup "info" to look for a malloc block that contains data + // that is the C string passed in aligned on a 1 byte boundary + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeAddress; // Check each block to see if the block + // contains the address passed in + data_info.addr = (uintptr_t)addr; // What data? The C string passed in + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + return g_matches.data(); +} diff --git a/examples/functions/Makefile b/examples/functions/Makefile new file mode 100644 index 000000000..64ea6e75b --- /dev/null +++ b/examples/functions/Makefile @@ -0,0 +1,18 @@ +LEVEL = ../../test/make + +CXX_SOURCES := main.cpp + +EXE := lldb-functions +USE_LIBCPP := 1 + +MY_OS = $(shell uname -s) + +ifeq "$(MY_OS)" "Darwin" + LLDB_BUILD_DIR ?= /Applications/Xcode.app/Contents/SharedFrameworks + LD_EXTRAS ?= -framework LLDB -Wl,-rpath,"$(LLDB_BUILD_DIR)" + FRAMEWORK_INCLUDES=-F"$(LLDB_BUILD_DIR)" +else + LD_EXTRAS ?= $(LLDB_BUILD_DIR)/_lldb.so +endif + +include $(LEVEL)/Makefile.rules diff --git a/examples/functions/main.cpp b/examples/functions/main.cpp new file mode 100644 index 000000000..bf0222334 --- /dev/null +++ b/examples/functions/main.cpp @@ -0,0 +1,346 @@ +//===-- 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 +#include +#include + +#if defined(__APPLE__) +#include +#else +#include "LLDB/SBBlock.h" +#include "LLDB/SBCompileUnit.h" +#include "LLDB/SBDebugger.h" +#include "LLDB/SBFunction.h" +#include "LLDB/SBModule.h" +#include "LLDB/SBProcess.h" +#include "LLDB/SBStream.h" +#include "LLDB/SBSymbol.h" +#include "LLDB/SBTarget.h" +#include "LLDB/SBThread.h" +#endif + +#include + +using namespace lldb; + +//---------------------------------------------------------------------- +// This quick sample code shows how to create a debugger instance and +// create an executable target without adding dependent shared +// libraries. It will then set a regular expression breakpoint to get +// breakpoint locations for all functions in the module, and use the +// locations to extract the symbol context for each location. Then it +// dumps all // information about the function: its name, file address +// range, the return type (if any), and all argument types. +// +// To build the program, type (while in this directory): +// +// $ make +// +// then to run this on MacOSX, specify the path to your LLDB.framework +// library using the DYLD_FRAMEWORK_PATH option and run the executable +// +// $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out +// executable_path1 [executable_path2 ...] +//---------------------------------------------------------------------- +class LLDBSentry { +public: + LLDBSentry() { + // Initialize LLDB + SBDebugger::Initialize(); + } + ~LLDBSentry() { + // Terminate LLDB + SBDebugger::Terminate(); + } +}; + +static struct option g_long_options[] = { + {"arch", required_argument, NULL, 'a'}, + {"canonical", no_argument, NULL, 'c'}, + {"extern", no_argument, NULL, 'x'}, + {"help", no_argument, NULL, 'h'}, + {"platform", required_argument, NULL, 'p'}, + {"verbose", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0}}; + +#define PROGRAM_NAME "lldb-functions" +void usage() { + puts("NAME\n" + " " PROGRAM_NAME + " -- extract all function signatures from one or more binaries.\n" + "\n" + "SYNOPSIS\n" + " " PROGRAM_NAME " [[--arch=] [--platform=] " + "[--verbose] [--help] [--canonical] --] " + "[....]\n" + "\n" + "DESCRIPTION\n" + " Loads the executable pointed to by and dumps complete " + "signatures for all functions that have debug information.\n" + "\n" + "EXAMPLE\n" + " " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n"); + exit(0); +} +int main(int argc, char const *argv[]) { + // Use a sentry object to properly initialize/terminate LLDB. + LLDBSentry sentry; + + SBDebugger debugger(SBDebugger::Create()); + + // Create a debugger instance so we can create a target + if (!debugger.IsValid()) + fprintf(stderr, "error: failed to create a debugger object\n"); + + bool show_usage = false; + bool verbose = false; + bool canonical = false; + bool external_only = false; + const char *arch = NULL; + const char *platform = NULL; + std::string short_options("h?"); + for (const struct option *opt = g_long_options; opt->name; ++opt) { + if (isprint(opt->val)) { + short_options.append(1, (char)opt->val); + switch (opt->has_arg) { + case no_argument: + break; + case required_argument: + short_options.append(1, ':'); + break; + case optional_argument: + short_options.append(2, ':'); + break; + } + } + } +#ifdef __GLIBC__ + optind = 0; +#else + optreset = 1; + optind = 1; +#endif + char ch; + while ((ch = getopt_long_only(argc, (char *const *)argv, + short_options.c_str(), g_long_options, 0)) != + -1) { + switch (ch) { + case 0: + break; + + case 'a': + if (arch != NULL) { + fprintf(stderr, + "error: the --arch option can only be specified once\n"); + exit(1); + } + arch = optarg; + break; + + case 'c': + canonical = true; + break; + + case 'x': + external_only = true; + break; + + case 'p': + platform = optarg; + break; + + case 'v': + verbose = true; + break; + + case 'h': + case '?': + default: + show_usage = true; + break; + } + } + argc -= optind; + argv += optind; + + const bool add_dependent_libs = false; + SBError error; + for (int arg_idx = 0; arg_idx < argc; ++arg_idx) { + // The first argument is the file path we want to look something up in + const char *exe_file_path = argv[arg_idx]; + + // Create a target using the executable. + SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform, + add_dependent_libs, error); + + if (error.Success()) { + if (target.IsValid()) { + SBFileSpec exe_file_spec(exe_file_path, true); + SBModule module(target.FindModule(exe_file_spec)); + SBFileSpecList comp_unit_list; + + if (module.IsValid()) { + char command[1024]; + lldb::SBCommandReturnObject command_result; + snprintf(command, sizeof(command), "add-dsym --uuid %s", + module.GetUUIDString()); + debugger.GetCommandInterpreter().HandleCommand(command, + command_result); + if (!command_result.Succeeded()) { + fprintf(stderr, "error: couldn't locate debug symbols for '%s'\n", + exe_file_path); + exit(1); + } + + SBFileSpecList module_list; + module_list.Append(exe_file_spec); + SBBreakpoint bp = + target.BreakpointCreateByRegex(".", module_list, comp_unit_list); + + const size_t num_locations = bp.GetNumLocations(); + for (uint32_t bp_loc_idx = 0; bp_loc_idx < num_locations; + ++bp_loc_idx) { + SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx); + SBSymbolContext sc( + bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything)); + if (sc.IsValid()) { + if (sc.GetBlock().GetContainingInlinedBlock().IsValid()) { + // Skip inlined functions + continue; + } + SBFunction function(sc.GetFunction()); + if (function.IsValid()) { + addr_t lo_pc = function.GetStartAddress().GetFileAddress(); + if (lo_pc == LLDB_INVALID_ADDRESS) { + // Skip functions that don't have concrete instances in the + // binary + continue; + } + addr_t hi_pc = function.GetEndAddress().GetFileAddress(); + const char *func_demangled_name = function.GetName(); + const char *func_mangled_name = function.GetMangledName(); + + bool dump = true; + const bool is_objc_method = ((func_demangled_name[0] == '-') || + (func_demangled_name[0] == '+')) && + (func_demangled_name[1] == '['); + if (external_only) { + // Dump all objective C methods, or external symbols + dump = is_objc_method; + if (!dump) + dump = sc.GetSymbol().IsExternal(); + } + + if (dump) { + if (verbose) { + printf("\n name: %s\n", func_demangled_name); + if (func_mangled_name) + printf("mangled: %s\n", func_mangled_name); + printf(" range: [0x%16.16llx - 0x%16.16llx)\n type: ", + lo_pc, hi_pc); + } else { + printf("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc); + } + SBType function_type = function.GetType(); + SBType return_type = function_type.GetFunctionReturnType(); + + if (canonical) + return_type = return_type.GetCanonicalType(); + + if (func_mangled_name && func_mangled_name[0] == '_' && + func_mangled_name[1] == 'Z') { + printf("%s %s\n", return_type.GetName(), + func_demangled_name); + } else { + SBTypeList function_args = + function_type.GetFunctionArgumentTypes(); + const size_t num_function_args = function_args.GetSize(); + + if (is_objc_method) { + const char *class_name_start = func_demangled_name + 2; + + if (num_function_args == 0) { + printf("%c(%s)[%s\n", func_demangled_name[0], + return_type.GetName(), class_name_start); + } else { + const char *class_name_end = + strchr(class_name_start, ' '); + const int class_name_len = + class_name_end - class_name_start; + printf("%c(%s)[%*.*s", func_demangled_name[0], + return_type.GetName(), class_name_len, + class_name_len, class_name_start); + + const char *selector_pos = class_name_end + 1; + for (uint32_t function_arg_idx = 0; + function_arg_idx < num_function_args; + ++function_arg_idx) { + const char *selector_end = + strchr(selector_pos, ':') + 1; + const int selector_len = selector_end - selector_pos; + SBType function_arg_type = + function_args.GetTypeAtIndex(function_arg_idx); + + if (canonical) + function_arg_type = + function_arg_type.GetCanonicalType(); + + printf(" %*.*s", selector_len, selector_len, + selector_pos); + if (function_arg_type.IsValid()) { + printf("(%s)", function_arg_type.GetName()); + } else { + printf("(?)"); + } + selector_pos = selector_end; + } + printf("]\n"); + } + } else { + printf("%s ", return_type.GetName()); + if (strchr(func_demangled_name, '(')) + printf("(*)("); + else + printf("%s(", func_demangled_name); + + for (uint32_t function_arg_idx = 0; + function_arg_idx < num_function_args; + ++function_arg_idx) { + SBType function_arg_type = + function_args.GetTypeAtIndex(function_arg_idx); + + if (canonical) + function_arg_type = + function_arg_type.GetCanonicalType(); + + if (function_arg_type.IsValid()) { + printf("%s%s", function_arg_idx > 0 ? ", " : "", + function_arg_type.GetName()); + } else { + printf("%s???", function_arg_idx > 0 ? ", " : ""); + } + } + printf(")\n"); + } + } + } + } + } + } + } + } + } else { + fprintf(stderr, "error: %s\n", error.GetCString()); + exit(1); + } + } + + return 0; +} diff --git a/examples/interposing/darwin/fd_interposing/FDInterposing.cpp b/examples/interposing/darwin/fd_interposing/FDInterposing.cpp new file mode 100644 index 000000000..105251c95 --- /dev/null +++ b/examples/interposing/darwin/fd_interposing/FDInterposing.cpp @@ -0,0 +1,985 @@ +//===-- FDInterposing.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file helps with catching double close calls on unix integer file +// descriptors by interposing functions for all file descriptor create and +// close operations. A stack backtrace for every create and close function is +// maintained, and every create and close operation is logged. When a double +// file descriptor close is encountered, it will be logged. +// +// To enable the interposing in a darwin program, set the DYLD_INSERT_LIBRARIES +// environment variable as follows: +// For sh: +// DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable +// For tcsh: +// (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; +// /path/to/executable) +// +// Other environment variables that can alter the default actions of this +// interposing shared library include: +// +// "FileDescriptorStackLoggingNoCompact" +// +// With this environment variable set, all file descriptor create and +// delete operations will be permanantly maintained in the event map. +// The default action is to compact the create/delete events by removing +// any previous file descriptor create events that are matched with a +// corresponding file descriptor delete event when the next valid file +// descriptor create event is detected. +// +// "FileDescriptorMinimalLogging" +// +// By default every file descriptor create and delete operation is logged +// (to STDOUT by default, see the "FileDescriptorLogFile"). This can be +// suppressed to only show errors and warnings by setting this environment +// variable (the value in not important). +// +// "FileDescriptorLogFile=" +// +// By default logging goes to STDOUT_FILENO, but this can be changed by +// setting FileDescriptorLogFile. The value is a path to a file that +// will be opened and used for logging. +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for std::tr1::shared_ptr +#include +#include + +//---------------------------------------------------------------------- +/// @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 &) + +extern "C" { +int accept$NOCANCEL(int, struct sockaddr *__restrict, socklen_t *__restrict); +int close$NOCANCEL(int); +int open$NOCANCEL(const char *, int, ...); +int __open_extended(const char *, int, uid_t, gid_t, int, + struct kauth_filesec *); +} + +namespace fd_interposing { + +//---------------------------------------------------------------------- +// String class so we can get formatted strings without having to worry +// about the memory storage since it will allocate the memory it needs. +//---------------------------------------------------------------------- +class String { +public: + String() : m_str(NULL) {} + + String(const char *format, ...) : m_str(NULL) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + } + + ~String() { reset(); } + + void reset(char *s = NULL) { + if (m_str) + ::free(m_str); + m_str = s; + } + + const char *c_str() const { return m_str; } + + void printf(const char *format, ...) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + } + void vprintf(const char *format, va_list args) { + reset(); + ::vasprintf(&m_str, format, args); + } + + void log(int log_fd) { + if (m_str && log_fd >= 0) { + const int len = strlen(m_str); + if (len > 0) { + write(log_fd, m_str, len); + const char last_char = m_str[len - 1]; + if (!(last_char == '\n' || last_char == '\r')) + write(log_fd, "\n", 1); + } + } + } + +protected: + char *m_str; + +private: + DISALLOW_COPY_AND_ASSIGN(String); +}; + +//---------------------------------------------------------------------- +// Type definitions +//---------------------------------------------------------------------- +typedef std::vector Frames; +class FDEvent; +typedef std::vector Frames; +typedef std::tr1::shared_ptr FDEventSP; +typedef std::tr1::shared_ptr StringSP; + +//---------------------------------------------------------------------- +// FDEvent +// +// A class that describes a file desciptor event. +// +// File descriptor events fall into one of two categories: create events +// and delete events. +//---------------------------------------------------------------------- +class FDEvent { +public: + FDEvent(int fd, int err, const StringSP &string_sp, bool is_create, + const Frames &frames) + : m_string_sp(string_sp), m_frames(frames.begin(), frames.end()), + m_fd(fd), m_err(err), m_is_create(is_create) {} + + ~FDEvent() {} + + bool IsCreateEvent() const { return m_is_create; } + + bool IsDeleteEvent() const { return !m_is_create; } + + Frames &GetFrames() { return m_frames; } + + const Frames &GetFrames() const { return m_frames; } + + int GetFD() const { return m_fd; } + + int GetError() const { return m_err; } + + void Dump(int log_fd) const; + + void SetCreateEvent(FDEventSP &create_event_sp) { + m_create_event_sp = create_event_sp; + } + +private: + // A shared pointer to a String that describes this event in + // detail (all args and return and error values) + StringSP m_string_sp; + // The frames for the stack backtrace for this event + Frames m_frames; + // If this is a file descriptor delete event, this might contain + // the correspoding file descriptor create event + FDEventSP m_create_event_sp; + // The file descriptor for this event + int m_fd; + // The error code (if any) for this event + int m_err; + // True if this event is a file descriptor create event, false + // if it is a file descriptor delete event + bool m_is_create; +}; + +//---------------------------------------------------------------------- +// Templatized class that will save errno only if the "value" it is +// constructed with is equal to INVALID. When the class goes out of +// scope, it will restore errno if it was saved. +//---------------------------------------------------------------------- +template class Errno { +public: + // Save errno only if we are supposed to + Errno(int value) + : m_saved_errno((value == INVALID) ? errno : 0), + m_restore(value == INVALID) {} + + // Restore errno only if we are supposed to + ~Errno() { + if (m_restore) + errno = m_saved_errno; + } + + // Accessor for the saved value of errno + int get_errno() const { return m_saved_errno; } + +protected: + const int m_saved_errno; + const bool m_restore; +}; + +typedef Errno<-1> InvalidFDErrno; +typedef Errno<-1> NegativeErrorErrno; +typedef std::vector FDEventArray; +typedef std::map FDEventMap; + +//---------------------------------------------------------------------- +// Globals +//---------------------------------------------------------------------- +// Global event map that contains all file descriptor events. As file +// descriptor create and close events come in, they will get filled +// into this map (protected by g_mutex). When a file descriptor close +// event is detected, the open event will be removed and placed into +// the close event so if something tries to double close a file +// descriptor we can show the previous close event and the file +// desctiptor event that created it. When a new file descriptor create +// event comes in, we will remove the previous one for that file +// desctiptor unless the environment variable +// "FileDescriptorStackLoggingNoCompact" +// is set. The file desctiptor history can be accessed using the +// get_fd_history() function. +static FDEventMap g_fd_event_map; +// A mutex to protect access to our data structures in g_fd_event_map +// and also our logging messages +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; +// Log all file descriptor create and close events by default. Only log +// warnings and erros if the "FileDescriptorMinimalLogging" environment +// variable is set. +static int g_log_all_calls = 1; +// We compact the file descriptor events by default. Set the environment +// varible "FileDescriptorStackLoggingNoCompact" to keep a full history. +static int g_compact = 1; +// The current process ID +static int g_pid = -1; +static bool g_enabled = true; +//---------------------------------------------------------------------- +// Mutex class that will lock a mutex when it is constructed, and unlock +// it when is goes out of scope +//---------------------------------------------------------------------- +class Locker { +public: + Locker(pthread_mutex_t *mutex_ptr) : m_mutex_ptr(mutex_ptr) { + ::pthread_mutex_lock(m_mutex_ptr); + } + + // This allows clients to test try and acquire the mutex... + Locker(pthread_mutex_t *mutex_ptr, bool &lock_acquired) : m_mutex_ptr(NULL) { + lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0; + if (lock_acquired) + m_mutex_ptr = mutex_ptr; + } + + ~Locker() { + if (m_mutex_ptr) + ::pthread_mutex_unlock(m_mutex_ptr); + } + +protected: + pthread_mutex_t *m_mutex_ptr; +}; + +static void log(const char *format, ...) __attribute__((format(printf, 1, 2))); + +static void log(int log_fd, const FDEvent *event, const char *format, ...) + __attribute__((format(printf, 3, 4))); + +static void backtrace_log(const char *format, ...) + __attribute__((format(printf, 1, 2))); + +static void backtrace_error(const char *format, ...) + __attribute__((format(printf, 1, 2))); + +static void log_to_fd(int log_fd, const char *format, ...) + __attribute__((format(printf, 2, 3))); + +static inline size_t get_backtrace(Frames &frame_buffer, + size_t frames_to_remove) { + void *frames[2048]; + int count = ::backtrace(&frames[0], sizeof(frames) / sizeof(void *)); + if (count > frames_to_remove) + frame_buffer.assign(&frames[frames_to_remove], &frames[count]); + else + frame_buffer.assign(&frames[0], &frames[count]); + while (frame_buffer.back() < (void *)1024) + frame_buffer.pop_back(); + return frame_buffer.size(); +} + +static int g_log_fd = STDOUT_FILENO; +static int g_initialized = 0; + +const char *get_process_fullpath(bool force = false) { + static char g_process_fullpath[PATH_MAX] = {0}; + if (force || g_process_fullpath[0] == '\0') { + // If DST is NULL, then return the number of bytes needed. + uint32_t len = sizeof(g_process_fullpath); + if (_NSGetExecutablePath(g_process_fullpath, &len) != 0) + strncpy(g_process_fullpath, "", sizeof(g_process_fullpath)); + } + return g_process_fullpath; +} + +// Returns the current process ID, or -1 if inserposing not enabled for +// this process +static int get_interposed_pid() { + if (!g_enabled) + return -1; + + const pid_t pid = getpid(); + if (g_pid != pid) { + if (g_pid == -1) { + g_pid = pid; + log("Interposing file descriptor create and delete functions for %s " + "(pid=%i)\n", + get_process_fullpath(true), pid); + } else { + log("pid=%i: disabling interposing file descriptor create and delete " + "functions for child process %s (pid=%i)\n", + g_pid, get_process_fullpath(true), pid); + g_enabled = false; + return -1; + } + // Log when our process changes + } + return g_pid; +} + +static int get_logging_fd() { + if (!g_enabled) + return -1; + + if (!g_initialized) { + g_initialized = 1; + + const pid_t pid = get_interposed_pid(); + + if (g_enabled) { + // Keep all stack info around for all fd create and delete calls. + // Otherwise we will remove the fd create call when a corresponding + // fd delete call is received + if (getenv("FileDescriptorStackLoggingNoCompact")) + g_compact = 0; + + if (getenv("FileDescriptorMinimalLogging")) + g_log_all_calls = 0; + + const char *log_path = getenv("FileDescriptorLogFile"); + if (log_path) + g_log_fd = ::creat(log_path, 0660); + else + g_log_fd = STDOUT_FILENO; + + // Only let this interposing happen on the first time this matches + // and stop this from happening so any child processes don't also + // log their file descriptors + ::unsetenv("DYLD_INSERT_LIBRARIES"); + } else { + log("pid=%i: logging disabled\n", getpid()); + } + } + return g_log_fd; +} + +void log_to_fd(int log_fd, const char *format, va_list args) { + if (format && format[0] && log_fd >= 0) { + char buffer[PATH_MAX]; + const int count = ::vsnprintf(buffer, sizeof(buffer), format, args); + if (count > 0) + write(log_fd, buffer, count); + } +} + +void log_to_fd(int log_fd, const char *format, ...) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log_to_fd(log_fd, format, args); + va_end(args); + } +} + +void log(const char *format, va_list args) { + log_to_fd(get_logging_fd(), format, args); +} + +void log(const char *format, ...) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log(format, args); + va_end(args); + } +} + +void log(int log_fd, const FDEvent *event, const char *format, ...) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log_to_fd(log_fd, format, args); + va_end(args); + } + if (event) + event->Dump(log_fd); +} + +void FDEvent::Dump(int log_fd) const { + if (log_fd >= 0) { + log_to_fd(log_fd, "%s\n", m_string_sp->c_str()); + if (!m_frames.empty()) + ::backtrace_symbols_fd(m_frames.data(), m_frames.size(), log_fd); + + if (m_create_event_sp) { + log_to_fd(log_fd, "\nfd=%i was created with this event:\n", m_fd); + m_create_event_sp->Dump(log_fd); + log_to_fd(log_fd, "\n"); + } + } +} + +void backtrace_log(const char *format, ...) { + const int log_fd = get_logging_fd(); + if (log_fd >= 0) { + if (format && format[0]) { + va_list args; + va_start(args, format); + log(format, args); + va_end(args); + } + + Frames frames; + if (get_backtrace(frames, 2)) + ::backtrace_symbols_fd(frames.data(), frames.size(), log_fd); + } +} + +void backtrace_error(const char *format, ...) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + const int log_fd = get_logging_fd(); + if (log_fd >= 0) { + log("\nerror: %s (pid=%i): ", get_process_fullpath(), pid); + + if (format && format[0]) { + va_list args; + va_start(args, format); + log(format, args); + va_end(args); + } + + Frames frames; + if (get_backtrace(frames, 2)) + ::backtrace_symbols_fd(frames.data(), frames.size(), log_fd); + } + } +} + +void save_backtrace(int fd, int err, const StringSP &string_sp, + bool is_create) { + Frames frames; + get_backtrace(frames, 2); + + FDEventSP fd_event_sp(new FDEvent(fd, err, string_sp, is_create, frames)); + + FDEventMap::iterator pos = g_fd_event_map.find(fd); + + if (pos != g_fd_event_map.end()) { + // We have history for this fd... + + FDEventArray &event_array = g_fd_event_map[fd]; + if (fd_event_sp->IsCreateEvent()) { + // The current fd event is a function that creates + // a descriptor, check in case last event was + // a create event. + if (event_array.back()->IsCreateEvent()) { + const int log_fd = get_logging_fd(); + // Two fd create functions in a row, we missed + // a function that closes a fd... + log(log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor " + "create event fd=%i (we missed a file " + "descriptor close event):\n", + fd); + } else if (g_compact) { + // We are compacting so we remove previous create event + // when we get the correspinding delete event + event_array.pop_back(); + } + } else { + // The current fd event is a function that deletes + // a descriptor, check in case last event for this + // fd was a delete event (double close!) + if (event_array.back()->IsDeleteEvent()) { + const int log_fd = get_logging_fd(); + // Two fd delete functions in a row, we must + // have missed some function that opened a descriptor + log(log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor " + "close event for fd=%d (we missed the " + "file descriptor create event):\n", + fd); + } else if (g_compact) { + // Since this is a close event, we want to remember the open event + // that this close if for... + fd_event_sp->SetCreateEvent(event_array.back()); + // We are compacting so we remove previous create event + // when we get the correspinding delete event + event_array.pop_back(); + } + } + + event_array.push_back(fd_event_sp); + } else { + g_fd_event_map[fd].push_back(fd_event_sp); + } +} + +//---------------------------------------------------------------------- +// socket() interpose function +//---------------------------------------------------------------------- +extern "C" int socket$__interposed__(int domain, int type, int protocol) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::socket(domain, type, protocol); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String); + if (fd == -1) + description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol " + "= %i) => fd=%i errno = %i", + pid, domain, type, protocol, fd, + fd_errno.get_errno()); + else + description_sp->printf( + "pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i", + pid, domain, type, protocol, fd); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::socket(domain, type, protocol); + } +} + +//---------------------------------------------------------------------- +// socketpair() interpose function +//---------------------------------------------------------------------- +extern "C" int socketpair$__interposed__(int domain, int type, int protocol, + int fds[2]) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + fds[0] = -1; + fds[1] = -1; + const int err = socketpair(domain, type, protocol, fds); + NegativeErrorErrno err_errno(err); + StringSP description_sp( + new String("pid=%i: socketpair (domain=%i, type=%i, protocol=%i, " + "{fd=%i, fd=%i}) -> err=%i", + pid, domain, type, protocol, fds[0], fds[1], err)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fds[0] >= 0) + save_backtrace(fds[0], err_errno.get_errno(), description_sp, true); + if (fds[1] >= 0) + save_backtrace(fds[1], err_errno.get_errno(), description_sp, true); + return err; + } else { + return socketpair(domain, type, protocol, fds); + } +} + +//---------------------------------------------------------------------- +// open() interpose function +//---------------------------------------------------------------------- +extern "C" int open$__interposed__(const char *path, int oflag, int mode) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + int fd = -2; + StringSP description_sp(new String); + if (oflag & O_CREAT) { + fd = ::open(path, oflag, mode); + description_sp->printf( + "pid=%i: open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, + path, oflag, mode, fd); + } else { + fd = ::open(path, oflag); + description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i", + pid, path, oflag, fd); + } + + InvalidFDErrno fd_errno(fd); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::open(path, oflag, mode); + } +} + +//---------------------------------------------------------------------- +// open$NOCANCEL() interpose function +//---------------------------------------------------------------------- +extern "C" int open$NOCANCEL$__interposed__(const char *path, int oflag, + int mode) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::open$NOCANCEL(path, oflag, mode); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", + pid, path, oflag, mode, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::open$NOCANCEL(path, oflag, mode); + } +} + +//---------------------------------------------------------------------- +// __open_extended() interpose function +//---------------------------------------------------------------------- +extern "C" int __open_extended$__interposed__(const char *path, int oflag, + uid_t uid, gid_t gid, int mode, + struct kauth_filesec *fsacl) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::__open_extended(path, oflag, uid, gid, mode, fsacl); + InvalidFDErrno fd_errno(fd); + StringSP description_sp( + new String("pid=%i: __open_extended (path='%s', oflag=%i, uid=%i, " + "gid=%i, mode=%i, fsacl=%p) -> fd=%i", + pid, path, oflag, uid, gid, mode, fsacl, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::__open_extended(path, oflag, uid, gid, mode, fsacl); + } +} + +//---------------------------------------------------------------------- +// kqueue() interpose function +//---------------------------------------------------------------------- +extern "C" int kqueue$__interposed__(void) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::kqueue(); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String("pid=%i: kqueue () -> fd=%i", pid, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::kqueue(); + } +} + +//---------------------------------------------------------------------- +// shm_open() interpose function +//---------------------------------------------------------------------- +extern "C" int shm_open$__interposed__(const char *path, int oflag, int mode) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::shm_open(path, oflag, mode); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, + path, oflag, mode, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::shm_open(path, oflag, mode); + } +} + +//---------------------------------------------------------------------- +// accept() interpose function +//---------------------------------------------------------------------- +extern "C" int accept$__interposed__(int socket, struct sockaddr *address, + socklen_t *address_len) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::accept(socket, address, address_len); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: accept (socket=%i, ...) -> fd=%i", pid, socket, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::accept(socket, address, address_len); + } +} + +//---------------------------------------------------------------------- +// accept$NOCANCEL() interpose function +//---------------------------------------------------------------------- +extern "C" int accept$NOCANCEL$__interposed__(int socket, + struct sockaddr *address, + socklen_t *address_len) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::accept$NOCANCEL(socket, address, address_len); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String( + "pid=%i: accept$NOCANCEL (socket=%i, ...) -> fd=%i", pid, socket, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::accept$NOCANCEL(socket, address, address_len); + } +} + +//---------------------------------------------------------------------- +// dup() interpose function +//---------------------------------------------------------------------- +extern "C" int dup$__interposed__(int fd2) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int fd = ::dup(fd2); + InvalidFDErrno fd_errno(fd); + StringSP description_sp( + new String("pid=%i: dup (fd2=%i) -> fd=%i", pid, fd2, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::dup(fd2); + } +} + +//---------------------------------------------------------------------- +// dup2() interpose function +//---------------------------------------------------------------------- +extern "C" int dup2$__interposed__(int fd1, int fd2) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + // If "fd2" is already opened, it will be closed during the + // dup2 call below, so we need to see if we have fd2 in our + // open map and treat it as a close(fd2) + FDEventMap::iterator pos = g_fd_event_map.find(fd2); + StringSP dup2_close_description_sp( + new String("pid=%i: dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", pid, + fd1, fd2, fd2)); + if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent()) + save_backtrace(fd2, 0, dup2_close_description_sp, false); + + const int fd = ::dup2(fd1, fd2); + InvalidFDErrno fd_errno(fd); + StringSP description_sp(new String("pid=%i: dup2 (fd1=%i, fd2=%i) -> fd=%i", + pid, fd1, fd2, fd)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + + if (fd >= 0) + save_backtrace(fd, fd_errno.get_errno(), description_sp, true); + return fd; + } else { + return ::dup2(fd1, fd2); + } +} + +//---------------------------------------------------------------------- +// close() interpose function +//---------------------------------------------------------------------- +extern "C" int close$__interposed__(int fd) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int err = close(fd); + NegativeErrorErrno err_errno(err); + StringSP description_sp(new String); + if (err == -1) + description_sp->printf("pid=%i: close (fd=%i) => %i errno = %i (%s))", + pid, fd, err, err_errno.get_errno(), + strerror(err_errno.get_errno())); + else + description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + + if (err == 0) { + if (fd >= 0) + save_backtrace(fd, err, description_sp, false); + } else if (err == -1) { + if (err_errno.get_errno() == EBADF && fd != -1) { + backtrace_error("close (fd=%d) resulted in EBADF:\n", fd); + + FDEventMap::iterator pos = g_fd_event_map.find(fd); + if (pos != g_fd_event_map.end()) { + log(get_logging_fd(), pos->second.back().get(), + "\nfd=%d was previously %s with this event:\n", fd, + pos->second.back()->IsCreateEvent() ? "opened" : "closed"); + } + } + } + return err; + } else { + return close(fd); + } +} + +//---------------------------------------------------------------------- +// close$NOCANCEL() interpose function +//---------------------------------------------------------------------- +extern "C" int close$NOCANCEL$__interposed__(int fd) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + const int err = close$NOCANCEL(fd); + NegativeErrorErrno err_errno(err); + StringSP description_sp(new String); + if (err == -1) + description_sp->printf( + "pid=%i: close$NOCANCEL (fd=%i) => %i errno = %i (%s))", pid, fd, err, + err_errno.get_errno(), strerror(err_errno.get_errno())); + else + description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i", pid, fd, + err); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + + if (err == 0) { + if (fd >= 0) + save_backtrace(fd, err, description_sp, false); + } else if (err == -1) { + if (err_errno.get_errno() == EBADF && fd != -1) { + backtrace_error("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd); + + FDEventMap::iterator pos = g_fd_event_map.find(fd); + if (pos != g_fd_event_map.end()) { + log(get_logging_fd(), pos->second.back().get(), + "\nfd=%d was previously %s with this event:\n", fd, + pos->second.back()->IsCreateEvent() ? "opened" : "closed"); + } + } + } + return err; + } else { + return close$NOCANCEL(fd); + } +} + +//---------------------------------------------------------------------- +// pipe() interpose function +//---------------------------------------------------------------------- +extern "C" int pipe$__interposed__(int fds[2]) { + const int pid = get_interposed_pid(); + if (pid >= 0) { + Locker locker(&g_mutex); + fds[0] = -1; + fds[1] = -1; + const int err = pipe(fds); + const int saved_errno = errno; + StringSP description_sp(new String( + "pid=%i: pipe ({fd=%i, fd=%i}) -> err=%i", pid, fds[0], fds[1], err)); + if (g_log_all_calls) + description_sp->log(get_logging_fd()); + if (fds[0] >= 0) + save_backtrace(fds[0], saved_errno, description_sp, true); + if (fds[1] >= 0) + save_backtrace(fds[1], saved_errno, description_sp, true); + errno = saved_errno; + return err; + } else { + return pipe(fds); + } +} + +//---------------------------------------------------------------------- +// get_fd_history() +// +// This function allows runtime access to the file descriptor history. +// +// @param[in] log_fd +// The file descriptor to log to +// +// @param[in] fd +// The file descriptor whose history should be dumped +//---------------------------------------------------------------------- +extern "C" void get_fd_history(int log_fd, int fd) { + // "create" below needs to be outside of the mutex locker scope + if (log_fd >= 0) { + bool got_lock = false; + Locker locker(&g_mutex, got_lock); + if (got_lock) { + FDEventMap::iterator pos = g_fd_event_map.find(fd); + log_to_fd(log_fd, "Dumping file descriptor history for fd=%i:\n", fd); + if (pos != g_fd_event_map.end()) { + FDEventArray &event_array = g_fd_event_map[fd]; + const size_t num_events = event_array.size(); + for (size_t i = 0; i < num_events; ++i) + event_array[i]->Dump(log_fd); + } else { + log_to_fd(log_fd, "error: no file descriptor events found for fd=%i\n", + fd); + } + } else { + log_to_fd(log_fd, "error: fd event mutex is locked...\n"); + } + } +} + +//---------------------------------------------------------------------- +// Interposing +//---------------------------------------------------------------------- +// FD creation routines +DYLD_INTERPOSE(accept$__interposed__, accept); +DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL); +DYLD_INTERPOSE(dup$__interposed__, dup); +DYLD_INTERPOSE(dup2$__interposed__, dup2); +DYLD_INTERPOSE(kqueue$__interposed__, kqueue); +DYLD_INTERPOSE(open$__interposed__, open); +DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL); +DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended); +DYLD_INTERPOSE(pipe$__interposed__, pipe); +DYLD_INTERPOSE(shm_open$__interposed__, shm_open); +DYLD_INTERPOSE(socket$__interposed__, socket); +DYLD_INTERPOSE(socketpair$__interposed__, socketpair); + +// FD deleting routines +DYLD_INTERPOSE(close$__interposed__, close); +DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL); + +} // namespace fd_interposing diff --git a/examples/interposing/darwin/fd_interposing/Makefile b/examples/interposing/darwin/fd_interposing/Makefile new file mode 100644 index 000000000..20570b1ec --- /dev/null +++ b/examples/interposing/darwin/fd_interposing/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../../test/make + +DYLIB_NAME := FDInterposing +DYLIB_ONLY := YES +DYLIB_CXX_SOURCES := FDInterposing.cpp + +include $(LEVEL)/Makefile.rules diff --git a/examples/lookup/Makefile b/examples/lookup/Makefile new file mode 100644 index 000000000..f4429b6e4 --- /dev/null +++ b/examples/lookup/Makefile @@ -0,0 +1,17 @@ +LEVEL = ../../test/make + +CXX_SOURCES := main.cpp +EXE := lldb-lookup +USE_LIBCPP := 1 + +MY_OS = $(shell uname -s) + +ifeq "$(MY_OS)" "Darwin" + LLDB_BUILD_DIR ?= /Applications/Xcode.app/Contents/SharedFrameworks + LD_EXTRAS ?= -framework LLDB -Wl,-rpath,"$(LLDB_BUILD_DIR)" + FRAMEWORK_INCLUDES=-F"$(LLDB_BUILD_DIR)" +else + LD_EXTRAS ?= $(LLDB_BUILD_DIR)/_lldb.so +endif + +include $(LEVEL)/Makefile.rules diff --git a/examples/lookup/main.cpp b/examples/lookup/main.cpp new file mode 100644 index 000000000..f2a3386ac --- /dev/null +++ b/examples/lookup/main.cpp @@ -0,0 +1,222 @@ +//===-- 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 +#include +#include + +#if defined(__APPLE__) +#include +#else +#include "LLDB/SBBlock.h" +#include "LLDB/SBCompileUnit.h" +#include "LLDB/SBDebugger.h" +#include "LLDB/SBFunction.h" +#include "LLDB/SBModule.h" +#include "LLDB/SBProcess.h" +#include "LLDB/SBStream.h" +#include "LLDB/SBSymbol.h" +#include "LLDB/SBTarget.h" +#include "LLDB/SBThread.h" +#endif + +#include + +using namespace lldb; + +//---------------------------------------------------------------------- +// This quick sample code shows how to create a debugger instance and +// create an "i386" executable target. Then we can lookup the executable +// module and resolve a file address into a section offset address, +// and find all symbol context objects (if any) for that address: +// compile unit, function, deepest block, line table entry and the +// symbol. +// +// To build the program, type (while in this directory): +// +// $ make +// +// then (for example): +// +// $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out +// executable_path file_address +//---------------------------------------------------------------------- +class LLDBSentry { +public: + LLDBSentry() { + // Initialize LLDB + SBDebugger::Initialize(); + } + ~LLDBSentry() { + // Terminate LLDB + SBDebugger::Terminate(); + } +}; + +static struct option g_long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"verbose", no_argument, NULL, 'v'}, + {"arch", required_argument, NULL, 'a'}, + {"platform", required_argument, NULL, 'p'}, + {NULL, 0, NULL, 0}}; + +#define PROGRAM_NAME "lldb-lookup" +void usage() { + puts("NAME\n" + " " PROGRAM_NAME " -- symbolicate addresses using lldb.\n" + "\n" + "SYNOPSIS\n" + " " PROGRAM_NAME " [[--arch=] [--platform=] " + "[--verbose] [--help] --]
" + "[
....]\n" + "\n" + "DESCRIPTION\n" + " Loads the executable pointed to by and looks up and " + "
\n" + " arguments\n" + "\n" + "EXAMPLE\n" + " " PROGRAM_NAME " --arch=x86_64 -- /usr/lib/dyld 0x100000000\n"); + exit(0); +} +int main(int argc, char const *argv[]) { + // Use a sentry object to properly initialize/terminate LLDB. + LLDBSentry sentry; + + SBDebugger debugger(SBDebugger::Create()); + + // Create a debugger instance so we can create a target + if (!debugger.IsValid()) + fprintf(stderr, "error: failed to create a debugger object\n"); + + bool show_usage = false; + bool verbose = false; + const char *arch = NULL; + const char *platform = NULL; + std::string short_options("h?"); + for (const struct option *opt = g_long_options; opt->name; ++opt) { + if (isprint(opt->val)) { + short_options.append(1, (char)opt->val); + switch (opt->has_arg) { + case no_argument: + break; + case required_argument: + short_options.append(1, ':'); + break; + case optional_argument: + short_options.append(2, ':'); + break; + } + } + } +#ifdef __GLIBC__ + optind = 0; +#else + optreset = 1; + optind = 1; +#endif + char ch; + while ((ch = getopt_long_only(argc, (char *const *)argv, + short_options.c_str(), g_long_options, 0)) != + -1) { + switch (ch) { + case 0: + break; + + case 'a': + if (arch != NULL) { + fprintf(stderr, + "error: the --arch option can only be specified once\n"); + exit(1); + } + arch = optarg; + break; + + case 'p': + platform = optarg; + break; + + case 'v': + verbose = true; + break; + + case 'h': + case '?': + default: + show_usage = true; + break; + } + } + argc -= optind; + argv += optind; + + if (show_usage || argc < 2) + usage(); + + int arg_idx = 0; + // The first argument is the file path we want to look something up in + const char *exe_file_path = argv[arg_idx]; + const char *addr_cstr; + const bool add_dependent_libs = false; + SBError error; + SBStream strm; + strm.RedirectToFileHandle(stdout, false); + + while ((addr_cstr = argv[++arg_idx]) != NULL) { + // The second argument in the address that we want to lookup + lldb::addr_t file_addr = strtoull(addr_cstr, NULL, 0); + + // Create a target using the executable. + SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform, + add_dependent_libs, error); + if (!error.Success()) { + fprintf(stderr, "error: %s\n", error.GetCString()); + exit(1); + } + + printf("%sLooking up 0x%llx in '%s':\n", (arg_idx > 1) ? "\n" : "", + file_addr, exe_file_path); + + if (target.IsValid()) { + // Find the executable module so we can do a lookup inside it + SBFileSpec exe_file_spec(exe_file_path, true); + SBModule module(target.FindModule(exe_file_spec)); + + // Take a file virtual address and resolve it to a section offset + // address that can be used to do a symbol lookup by address + SBAddress addr = module.ResolveFileAddress(file_addr); + bool success = addr.IsValid() && addr.GetSection().IsValid(); + if (success) { + // We can resolve a section offset address in the module + // and only ask for what we need. You can logical or together + // bits from the SymbolContextItem enumeration found in + // lldb-enumeration.h to request only what you want. Here we + // are asking for everything. + // + // NOTE: the less you ask for, the less LLDB will parse as + // LLDB does partial parsing on just about everything. + SBSymbolContext sc(module.ResolveSymbolContextForAddress( + addr, eSymbolContextEverything)); + + strm.Printf(" Address: %s + 0x%llx\n Summary: ", + addr.GetSection().GetName(), addr.GetOffset()); + addr.GetDescription(strm); + strm.Printf("\n"); + if (verbose) + sc.GetDescription(strm); + } else { + printf( + "error: 0x%llx does not resolve to a valid file address in '%s'\n", + file_addr, exe_file_path); + } + } + } + + return 0; +} diff --git a/examples/plugins/commands/fooplugin.cpp b/examples/plugins/commands/fooplugin.cpp new file mode 100644 index 000000000..ae11cd759 --- /dev/null +++ b/examples/plugins/commands/fooplugin.cpp @@ -0,0 +1,47 @@ +//===-- fooplugin.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +/* +An example plugin for LLDB that provides a new foo command with a child +subcommand +Compile this into a dylib foo.dylib and load by placing in appropriate locations +on disk or +by typing plugin load foo.dylib at the LLDB command line +*/ + +#include +#include +#include + +namespace lldb { +bool PluginInitialize(lldb::SBDebugger debugger); +} + +class ChildCommand : public lldb::SBCommandPluginInterface { +public: + virtual bool DoExecute(lldb::SBDebugger debugger, char **command, + lldb::SBCommandReturnObject &result) { + if (command) { + const char *arg = *command; + while (arg) { + result.Printf("%s\n", arg); + arg = *(++command); + } + return true; + } + return false; + } +}; + +bool lldb::PluginInitialize(lldb::SBDebugger debugger) { + lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter(); + lldb::SBCommand foo = interpreter.AddMultiwordCommand("foo", NULL); + foo.AddCommand("child", new ChildCommand(), "a child of foo"); + return true; +} diff --git a/examples/python/cmdtemplate.py b/examples/python/cmdtemplate.py new file mode 100644 index 000000000..dfe3e6fa5 --- /dev/null +++ b/examples/python/cmdtemplate.py @@ -0,0 +1,112 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# +# # To use this in the embedded python interpreter using "lldb" just +# import it with the full path using the "command script import" +# command +# (lldb) command script import /path/to/cmdtemplate.py +#---------------------------------------------------------------------- + +import lldb +import commands +import optparse +import shlex + + +def create_framestats_options(): + usage = "usage: %prog [options]" + description = '''This command is meant to be an example of how to make an LLDB command that +does something useful, follows best practices, and exploits the SB API. +Specifically, this command computes the aggregate and average size of the variables in the current frame +and allows you to tweak exactly which variables are to be accounted in the computation. +''' + parser = optparse.OptionParser( + description=description, + prog='framestats', + usage=usage) + parser.add_option( + '-i', + '--in-scope', + action='store_true', + dest='inscope', + help='in_scope_only = True', + default=False) + parser.add_option( + '-a', + '--arguments', + action='store_true', + dest='arguments', + help='arguments = True', + default=False) + parser.add_option( + '-l', + '--locals', + action='store_true', + dest='locals', + help='locals = True', + default=False) + parser.add_option( + '-s', + '--statics', + action='store_true', + dest='statics', + help='statics = True', + default=False) + return parser + + +def the_framestats_command(debugger, command, result, dict): + # Use the Shell Lexer to properly parse up command options just like a + # shell would + command_args = shlex.split(command) + parser = create_framestats_options() + try: + (options, args) = parser.parse_args(command_args) + except: + # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit + # (courtesy of OptParse dealing with argument errors by throwing SystemExit) + result.SetError("option parsing failed") + return + + # in a command - the lldb.* convenience variables are not to be used + # and their values (if any) are undefined + # this is the best practice to access those objects from within a command + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + if not frame.IsValid(): + return "no frame here" + # from now on, replace lldb..whatever with .whatever + variables_list = frame.GetVariables( + options.arguments, + options.locals, + options.statics, + options.inscope) + variables_count = variables_list.GetSize() + if variables_count == 0: + print >> result, "no variables here" + return + total_size = 0 + for i in range(0, variables_count): + variable = variables_list.GetValueAtIndex(i) + variable_type = variable.GetType() + total_size = total_size + variable_type.GetByteSize() + average_size = float(total_size) / variables_count + print >>result, "Your frame has %d variables. Their total size is %d bytes. The average size is %f bytes" % ( + variables_count, total_size, average_size) + # not returning anything is akin to returning success + + +def __lldb_init_module(debugger, dict): + # This initializer is being run from LLDB in the embedded command interpreter + # Make the options so we can generate the help text for the new LLDB + # command line command prior to registering it with LLDB below + parser = create_framestats_options() + the_framestats_command.__doc__ = parser.format_help() + # Add any commands contained in this module to LLDB + debugger.HandleCommand( + 'command script add -f cmdtemplate.the_framestats_command framestats') + print 'The "framestats" command has been installed, type "help framestats" or "framestats --help" for detailed help.' diff --git a/examples/python/crashlog.py b/examples/python/crashlog.py new file mode 100755 index 000000000..7270f60f4 --- /dev/null +++ b/examples/python/crashlog.py @@ -0,0 +1,1015 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# +# To use this in the embedded python interpreter using "lldb": +# +# cd /path/containing/crashlog.py +# lldb +# (lldb) script import crashlog +# "crashlog" command installed, type "crashlog --help" for detailed help +# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash +# +# The benefit of running the crashlog command inside lldb in the +# embedded python interpreter is when the command completes, there +# will be a target with all of the files loaded at the locations +# described in the crash log. Only the files that have stack frames +# in the backtrace will be loaded unless the "--load-all" option +# has been specified. This allows users to explore the program in the +# state it was in right at crash time. +# +# On MacOSX csh, tcsh: +# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) +# +# On MacOSX sh, bash: +# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash +#---------------------------------------------------------------------- + +import commands +import cmd +import datetime +import glob +import optparse +import os +import platform +import plistlib +import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args) +import re +import shlex +import string +import sys +import time +import uuid + +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append( + os.path.realpath( + xcode_dir + + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append( + xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append( + '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + +from lldb.utils import symbolication + +PARSE_MODE_NORMAL = 0 +PARSE_MODE_THREAD = 1 +PARSE_MODE_IMAGES = 2 +PARSE_MODE_THREGS = 3 +PARSE_MODE_SYSTEM = 4 + + +class CrashLog(symbolication.Symbolicator): + """Class that does parses darwin crash logs""" + parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]') + thread_state_regex = re.compile('^Thread ([0-9]+) crashed with') + thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)') + app_backtrace_regex = re.compile( + '^Application Specific Backtrace ([0-9]+)([^:]*):(.*)') + frame_regex = re.compile('^([0-9]+)\s+([^ ]+)\s+(0x[0-9a-fA-F]+) +(.*)') + image_regex_uuid = re.compile( + '(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^<]+)<([-0-9a-fA-F]+)> (.*)') + image_regex_no_uuid = re.compile( + '(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^/]+)/(.*)') + empty_line_regex = re.compile('^$') + + class Thread: + """Class that represents a thread in a darwin crash log""" + + def __init__(self, index, app_specific_backtrace): + self.index = index + self.frames = list() + self.idents = list() + self.registers = dict() + self.reason = None + self.queue = None + self.app_specific_backtrace = app_specific_backtrace + + def dump(self, prefix): + if self.app_specific_backtrace: + print "%Application Specific Backtrace[%u] %s" % (prefix, self.index, self.reason) + else: + print "%sThread[%u] %s" % (prefix, self.index, self.reason) + if self.frames: + print "%s Frames:" % (prefix) + for frame in self.frames: + frame.dump(prefix + ' ') + if self.registers: + print "%s Registers:" % (prefix) + for reg in self.registers.keys(): + print "%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg]) + + def dump_symbolicated(self, crash_log, options): + this_thread_crashed = self.app_specific_backtrace + if not this_thread_crashed: + this_thread_crashed = self.did_crash() + if options.crashed_only and this_thread_crashed == False: + return + + print "%s" % self + #prev_frame_index = -1 + display_frame_idx = -1 + for frame_idx, frame in enumerate(self.frames): + disassemble = ( + this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth + if frame_idx == 0: + symbolicated_frame_addresses = crash_log.symbolicate( + frame.pc & crash_log.addr_mask, options.verbose) + else: + # Any frame above frame zero and we have to subtract one to + # get the previous line entry + symbolicated_frame_addresses = crash_log.symbolicate( + (frame.pc & crash_log.addr_mask) - 1, options.verbose) + + if symbolicated_frame_addresses: + symbolicated_frame_address_idx = 0 + for symbolicated_frame_address in symbolicated_frame_addresses: + display_frame_idx += 1 + print '[%3u] %s' % (frame_idx, symbolicated_frame_address) + if (options.source_all or self.did_crash( + )) and display_frame_idx < options.source_frames and options.source_context: + source_context = options.source_context + line_entry = symbolicated_frame_address.get_symbol_context().line_entry + if line_entry.IsValid(): + strm = lldb.SBStream() + if line_entry: + lldb.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers( + line_entry.file, line_entry.line, source_context, source_context, "->", strm) + source_text = strm.GetData() + if source_text: + # Indent the source a bit + indent_str = ' ' + join_str = '\n' + indent_str + print '%s%s' % (indent_str, join_str.join(source_text.split('\n'))) + if symbolicated_frame_address_idx == 0: + if disassemble: + instructions = symbolicated_frame_address.get_instructions() + if instructions: + print + symbolication.disassemble_instructions( + crash_log.get_target(), + instructions, + frame.pc, + options.disassemble_before, + options.disassemble_after, + frame.index > 0) + print + symbolicated_frame_address_idx += 1 + else: + print frame + + def add_ident(self, ident): + if ident not in self.idents: + self.idents.append(ident) + + def did_crash(self): + return self.reason is not None + + def __str__(self): + if self.app_specific_backtrace: + s = "Application Specific Backtrace[%u]" % self.index + else: + s = "Thread[%u]" % self.index + if self.reason: + s += ' %s' % self.reason + return s + + class Frame: + """Class that represents a stack frame in a thread in a darwin crash log""" + + def __init__(self, index, pc, description): + self.pc = pc + self.description = description + self.index = index + + def __str__(self): + if self.description: + return "[%3u] 0x%16.16x %s" % ( + self.index, self.pc, self.description) + else: + return "[%3u] 0x%16.16x" % (self.index, self.pc) + + def dump(self, prefix): + print "%s%s" % (prefix, str(self)) + + class DarwinImage(symbolication.Image): + """Class that represents a binary images in a darwin crash log""" + dsymForUUIDBinary = os.path.expanduser('~rc/bin/dsymForUUID') + if not os.path.exists(dsymForUUIDBinary): + dsymForUUIDBinary = commands.getoutput('which dsymForUUID') + + dwarfdump_uuid_regex = re.compile( + 'UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*') + + def __init__( + self, + text_addr_lo, + text_addr_hi, + identifier, + version, + uuid, + path): + symbolication.Image.__init__(self, path, uuid) + self.add_section( + symbolication.Section( + text_addr_lo, + text_addr_hi, + "__TEXT")) + self.identifier = identifier + self.version = version + + def locate_module_and_debug_symbols(self): + # Don't load a module twice... + if self.resolved: + return True + # Mark this as resolved so we don't keep trying + self.resolved = True + uuid_str = self.get_normalized_uuid_string() + print 'Getting symbols for %s %s...' % (uuid_str, self.path), + if os.path.exists(self.dsymForUUIDBinary): + dsym_for_uuid_command = '%s %s' % ( + self.dsymForUUIDBinary, uuid_str) + s = commands.getoutput(dsym_for_uuid_command) + if s: + try: + plist_root = plistlib.readPlistFromString(s) + except: + print("Got exception: ", sys.exc_value, " handling dsymForUUID output: \n", s) + raise + if plist_root: + plist = plist_root[uuid_str] + if plist: + if 'DBGArchitecture' in plist: + self.arch = plist['DBGArchitecture'] + if 'DBGDSYMPath' in plist: + self.symfile = os.path.realpath( + plist['DBGDSYMPath']) + if 'DBGSymbolRichExecutable' in plist: + self.path = os.path.expanduser( + plist['DBGSymbolRichExecutable']) + self.resolved_path = self.path + if not self.resolved_path and os.path.exists(self.path): + dwarfdump_cmd_output = commands.getoutput( + 'dwarfdump --uuid "%s"' % self.path) + self_uuid = self.get_uuid() + for line in dwarfdump_cmd_output.splitlines(): + match = self.dwarfdump_uuid_regex.search(line) + if match: + dwarf_uuid_str = match.group(1) + dwarf_uuid = uuid.UUID(dwarf_uuid_str) + if self_uuid == dwarf_uuid: + self.resolved_path = self.path + self.arch = match.group(2) + break + if not self.resolved_path: + self.unavailable = True + print "error\n error: unable to locate '%s' with UUID %s" % (self.path, uuid_str) + return False + if (self.resolved_path and os.path.exists(self.resolved_path)) or ( + self.path and os.path.exists(self.path)): + print 'ok' + # if self.resolved_path: + # print ' exe = "%s"' % self.resolved_path + # if self.symfile: + # print ' dsym = "%s"' % self.symfile + return True + else: + self.unavailable = True + return False + + def __init__(self, path): + """CrashLog constructor that take a path to a darwin crash log file""" + symbolication.Symbolicator.__init__(self) + self.path = os.path.expanduser(path) + self.info_lines = list() + self.system_profile = list() + self.threads = list() + self.backtraces = list() # For application specific backtraces + self.idents = list() # A list of the required identifiers for doing all stack backtraces + self.crashed_thread_idx = -1 + self.version = -1 + self.error = None + self.target = None + # With possible initial component of ~ or ~user replaced by that user's + # home directory. + try: + f = open(self.path) + except IOError: + self.error = 'error: cannot open "%s"' % self.path + return + + self.file_lines = f.read().splitlines() + parse_mode = PARSE_MODE_NORMAL + thread = None + app_specific_backtrace = False + for line in self.file_lines: + # print line + line_len = len(line) + if line_len == 0: + if thread: + if parse_mode == PARSE_MODE_THREAD: + if thread.index == self.crashed_thread_idx: + thread.reason = '' + if self.thread_exception: + thread.reason += self.thread_exception + if self.thread_exception_data: + thread.reason += " (%s)" % self.thread_exception_data + if app_specific_backtrace: + self.backtraces.append(thread) + else: + self.threads.append(thread) + thread = None + else: + # only append an extra empty line if the previous line + # in the info_lines wasn't empty + if len(self.info_lines) > 0 and len(self.info_lines[-1]): + self.info_lines.append(line) + parse_mode = PARSE_MODE_NORMAL + # print 'PARSE_MODE_NORMAL' + elif parse_mode == PARSE_MODE_NORMAL: + if line.startswith('Process:'): + (self.process_name, pid_with_brackets) = line[ + 8:].strip().split(' [') + self.process_id = pid_with_brackets.strip('[]') + elif line.startswith('Path:'): + self.process_path = line[5:].strip() + elif line.startswith('Identifier:'): + self.process_identifier = line[11:].strip() + elif line.startswith('Version:'): + version_string = line[8:].strip() + matched_pair = re.search("(.+)\((.+)\)", version_string) + if matched_pair: + self.process_version = matched_pair.group(1) + self.process_compatability_version = matched_pair.group( + 2) + else: + self.process = version_string + self.process_compatability_version = version_string + elif self.parent_process_regex.search(line): + parent_process_match = self.parent_process_regex.search( + line) + self.parent_process_name = parent_process_match.group(1) + self.parent_process_id = parent_process_match.group(2) + elif line.startswith('Exception Type:'): + self.thread_exception = line[15:].strip() + continue + elif line.startswith('Exception Codes:'): + self.thread_exception_data = line[16:].strip() + continue + elif line.startswith('Exception Subtype:'): # iOS + self.thread_exception_data = line[18:].strip() + continue + elif line.startswith('Crashed Thread:'): + self.crashed_thread_idx = int(line[15:].strip().split()[0]) + continue + elif line.startswith('Triggered by Thread:'): # iOS + self.crashed_thread_idx = int(line[20:].strip().split()[0]) + continue + elif line.startswith('Report Version:'): + self.version = int(line[15:].strip()) + continue + elif line.startswith('System Profile:'): + parse_mode = PARSE_MODE_SYSTEM + continue + elif (line.startswith('Interval Since Last Report:') or + line.startswith('Crashes Since Last Report:') or + line.startswith('Per-App Interval Since Last Report:') or + line.startswith('Per-App Crashes Since Last Report:') or + line.startswith('Sleep/Wake UUID:') or + line.startswith('Anonymous UUID:')): + # ignore these + continue + elif line.startswith('Thread'): + thread_state_match = self.thread_state_regex.search(line) + if thread_state_match: + app_specific_backtrace = False + thread_state_match = self.thread_regex.search(line) + thread_idx = int(thread_state_match.group(1)) + parse_mode = PARSE_MODE_THREGS + thread = self.threads[thread_idx] + else: + thread_match = self.thread_regex.search(line) + if thread_match: + app_specific_backtrace = False + parse_mode = PARSE_MODE_THREAD + thread_idx = int(thread_match.group(1)) + thread = CrashLog.Thread(thread_idx, False) + continue + elif line.startswith('Binary Images:'): + parse_mode = PARSE_MODE_IMAGES + continue + elif line.startswith('Application Specific Backtrace'): + app_backtrace_match = self.app_backtrace_regex.search(line) + if app_backtrace_match: + parse_mode = PARSE_MODE_THREAD + app_specific_backtrace = True + idx = int(app_backtrace_match.group(1)) + thread = CrashLog.Thread(idx, True) + elif line.startswith('Last Exception Backtrace:'): # iOS + parse_mode = PARSE_MODE_THREAD + app_specific_backtrace = True + idx = 1 + thread = CrashLog.Thread(idx, True) + self.info_lines.append(line.strip()) + elif parse_mode == PARSE_MODE_THREAD: + if line.startswith('Thread'): + continue + frame_match = self.frame_regex.search(line) + if frame_match: + ident = frame_match.group(2) + thread.add_ident(ident) + if ident not in self.idents: + self.idents.append(ident) + thread.frames.append(CrashLog.Frame(int(frame_match.group(1)), int( + frame_match.group(3), 0), frame_match.group(4))) + else: + print 'error: frame regex failed for line: "%s"' % line + elif parse_mode == PARSE_MODE_IMAGES: + image_match = self.image_regex_uuid.search(line) + if image_match: + image = CrashLog.DarwinImage(int(image_match.group(1), 0), + int(image_match.group(2), 0), + image_match.group(3).strip(), + image_match.group(4).strip(), + uuid.UUID(image_match.group(5)), + image_match.group(6)) + self.images.append(image) + else: + image_match = self.image_regex_no_uuid.search(line) + if image_match: + image = CrashLog.DarwinImage(int(image_match.group(1), 0), + int(image_match.group(2), 0), + image_match.group(3).strip(), + image_match.group(4).strip(), + None, + image_match.group(5)) + self.images.append(image) + else: + print "error: image regex failed for: %s" % line + + elif parse_mode == PARSE_MODE_THREGS: + stripped_line = line.strip() + # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00" + reg_values = re.findall( + '([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line) + for reg_value in reg_values: + # print 'reg_value = "%s"' % reg_value + (reg, value) = reg_value.split(': ') + # print 'reg = "%s"' % reg + # print 'value = "%s"' % value + thread.registers[reg.strip()] = int(value, 0) + elif parse_mode == PARSE_MODE_SYSTEM: + self.system_profile.append(line) + f.close() + + def dump(self): + print "Crash Log File: %s" % (self.path) + if self.backtraces: + print "\nApplication Specific Backtraces:" + for thread in self.backtraces: + thread.dump(' ') + print "\nThreads:" + for thread in self.threads: + thread.dump(' ') + print "\nImages:" + for image in self.images: + image.dump(' ') + + def find_image_with_identifier(self, identifier): + for image in self.images: + if image.identifier == identifier: + return image + regex_text = '^.*\.%s$' % (re.escape(identifier)) + regex = re.compile(regex_text) + for image in self.images: + if regex.match(image.identifier): + return image + return None + + def create_target(self): + # print 'crashlog.create_target()...' + if self.target is None: + self.target = symbolication.Symbolicator.create_target(self) + if self.target: + return self.target + # We weren't able to open the main executable as, but we can still + # symbolicate + print 'crashlog.create_target()...2' + if self.idents: + for ident in self.idents: + image = self.find_image_with_identifier(ident) + if image: + self.target = image.create_target() + if self.target: + return self.target # success + print 'crashlog.create_target()...3' + for image in self.images: + self.target = image.create_target() + if self.target: + return self.target # success + print 'crashlog.create_target()...4' + print 'error: unable to locate any executables from the crash log' + return self.target + + def get_target(self): + return self.target + + +def usage(): + print "Usage: lldb-symbolicate.py [-n name] executable-image" + sys.exit(0) + + +class Interactive(cmd.Cmd): + '''Interactive prompt for analyzing one or more Darwin crash logs, type "help" to see a list of supported commands.''' + image_option_parser = None + + def __init__(self, crash_logs): + cmd.Cmd.__init__(self) + self.use_rawinput = False + self.intro = 'Interactive crashlogs prompt, type "help" to see a list of supported commands.' + self.crash_logs = crash_logs + self.prompt = '% ' + + def default(self, line): + '''Catch all for unknown command, which will exit the interpreter.''' + print "uknown command: %s" % line + return True + + def do_q(self, line): + '''Quit command''' + return True + + def do_quit(self, line): + '''Quit command''' + return True + + def do_symbolicate(self, line): + description = '''Symbolicate one or more darwin crash log files by index to provide source file and line information, + inlined stack frames back to the concrete functions, and disassemble the location of the crash + for the first frame of the crashed thread.''' + option_parser = CreateSymbolicateCrashLogOptions( + 'symbolicate', description, False) + command_args = shlex.split(line) + try: + (options, args) = option_parser.parse_args(command_args) + except: + return + + if args: + # We have arguments, they must valid be crash log file indexes + for idx_str in args: + idx = int(idx_str) + if idx < len(self.crash_logs): + SymbolicateCrashLog(self.crash_logs[idx], options) + else: + print 'error: crash log index %u is out of range' % (idx) + else: + # No arguments, symbolicate all crash logs using the options + # provided + for idx in range(len(self.crash_logs)): + SymbolicateCrashLog(self.crash_logs[idx], options) + + def do_list(self, line=None): + '''Dump a list of all crash logs that are currently loaded. + + USAGE: list''' + print '%u crash logs are loaded:' % len(self.crash_logs) + for (crash_log_idx, crash_log) in enumerate(self.crash_logs): + print '[%u] = %s' % (crash_log_idx, crash_log.path) + + def do_image(self, line): + '''Dump information about one or more binary images in the crash log given an image basename, or all images if no arguments are provided.''' + usage = "usage: %prog [options] [PATH ...]" + description = '''Dump information about one or more images in all crash logs. The can be a full path, image basename, or partial path. Searches are done in this order.''' + command_args = shlex.split(line) + if not self.image_option_parser: + self.image_option_parser = optparse.OptionParser( + description=description, prog='image', usage=usage) + self.image_option_parser.add_option( + '-a', + '--all', + action='store_true', + help='show all images', + default=False) + try: + (options, args) = self.image_option_parser.parse_args(command_args) + except: + return + + if args: + for image_path in args: + fullpath_search = image_path[0] == '/' + for (crash_log_idx, crash_log) in enumerate(self.crash_logs): + matches_found = 0 + for (image_idx, image) in enumerate(crash_log.images): + if fullpath_search: + if image.get_resolved_path() == image_path: + matches_found += 1 + print '[%u] ' % (crash_log_idx), image + else: + image_basename = image.get_resolved_path_basename() + if image_basename == image_path: + matches_found += 1 + print '[%u] ' % (crash_log_idx), image + if matches_found == 0: + for (image_idx, image) in enumerate(crash_log.images): + resolved_image_path = image.get_resolved_path() + if resolved_image_path and string.find( + image.get_resolved_path(), image_path) >= 0: + print '[%u] ' % (crash_log_idx), image + else: + for crash_log in self.crash_logs: + for (image_idx, image) in enumerate(crash_log.images): + print '[%u] %s' % (image_idx, image) + return False + + +def interactive_crashlogs(options, args): + crash_log_files = list() + for arg in args: + for resolved_path in glob.glob(arg): + crash_log_files.append(resolved_path) + + crash_logs = list() + for crash_log_file in crash_log_files: + # print 'crash_log_file = "%s"' % crash_log_file + crash_log = CrashLog(crash_log_file) + if crash_log.error: + print crash_log.error + continue + if options.debug: + crash_log.dump() + if not crash_log.images: + print 'error: no images in crash log "%s"' % (crash_log) + continue + else: + crash_logs.append(crash_log) + + interpreter = Interactive(crash_logs) + # List all crash logs that were imported + interpreter.do_list() + interpreter.cmdloop() + + +def save_crashlog(debugger, command, result, dict): + usage = "usage: %prog [options] " + description = '''Export the state of current target into a crashlog file''' + parser = optparse.OptionParser( + description=description, + prog='save_crashlog', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + try: + (options, args) = parser.parse_args(shlex.split(command)) + except: + result.PutCString("error: invalid options") + return + if len(args) != 1: + result.PutCString( + "error: invalid arguments, a single output file is the only valid argument") + return + out_file = open(args[0], 'w') + if not out_file: + result.PutCString( + "error: failed to open file '%s' for writing...", + args[0]) + return + target = debugger.GetSelectedTarget() + if target: + identifier = target.executable.basename + if lldb.process: + pid = lldb.process.id + if pid != lldb.LLDB_INVALID_PROCESS_ID: + out_file.write( + 'Process: %s [%u]\n' % + (identifier, pid)) + out_file.write('Path: %s\n' % (target.executable.fullpath)) + out_file.write('Identifier: %s\n' % (identifier)) + out_file.write('\nDate/Time: %s\n' % + (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))) + out_file.write( + 'OS Version: Mac OS X %s (%s)\n' % + (platform.mac_ver()[0], commands.getoutput('sysctl -n kern.osversion'))) + out_file.write('Report Version: 9\n') + for thread_idx in range(lldb.process.num_threads): + thread = lldb.process.thread[thread_idx] + out_file.write('\nThread %u:\n' % (thread_idx)) + for (frame_idx, frame) in enumerate(thread.frames): + frame_pc = frame.pc + frame_offset = 0 + if frame.function: + block = frame.GetFrameBlock() + block_range = block.range[frame.addr] + if block_range: + block_start_addr = block_range[0] + frame_offset = frame_pc - block_start_addr.load_addr + else: + frame_offset = frame_pc - frame.function.addr.load_addr + elif frame.symbol: + frame_offset = frame_pc - frame.symbol.addr.load_addr + out_file.write( + '%-3u %-32s 0x%16.16x %s' % + (frame_idx, frame.module.file.basename, frame_pc, frame.name)) + if frame_offset > 0: + out_file.write(' + %u' % (frame_offset)) + line_entry = frame.line_entry + if line_entry: + if options.verbose: + # This will output the fullpath + line + column + out_file.write(' %s' % (line_entry)) + else: + out_file.write( + ' %s:%u' % + (line_entry.file.basename, line_entry.line)) + column = line_entry.column + if column: + out_file.write(':%u' % (column)) + out_file.write('\n') + + out_file.write('\nBinary Images:\n') + for module in target.modules: + text_segment = module.section['__TEXT'] + if text_segment: + text_segment_load_addr = text_segment.GetLoadAddress(target) + if text_segment_load_addr != lldb.LLDB_INVALID_ADDRESS: + text_segment_end_load_addr = text_segment_load_addr + text_segment.size + identifier = module.file.basename + module_version = '???' + module_version_array = module.GetVersion() + if module_version_array: + module_version = '.'.join( + map(str, module_version_array)) + out_file.write( + ' 0x%16.16x - 0x%16.16x %s (%s - ???) <%s> %s\n' % + (text_segment_load_addr, + text_segment_end_load_addr, + identifier, + module_version, + module.GetUUIDString(), + module.file.fullpath)) + out_file.close() + else: + result.PutCString("error: invalid target") + + +def Symbolicate(debugger, command, result, dict): + try: + SymbolicateCrashLogs(shlex.split(command)) + except: + result.PutCString("error: python exception %s" % sys.exc_info()[0]) + + +def SymbolicateCrashLog(crash_log, options): + if crash_log.error: + print crash_log.error + return + if options.debug: + crash_log.dump() + if not crash_log.images: + print 'error: no images in crash log' + return + + if options.dump_image_list: + print "Binary Images:" + for image in crash_log.images: + if options.verbose: + print image.debug_dump() + else: + print image + + target = crash_log.create_target() + if not target: + return + exe_module = target.GetModuleAtIndex(0) + images_to_load = list() + loaded_images = list() + if options.load_all_images: + # --load-all option was specified, load everything up + for image in crash_log.images: + images_to_load.append(image) + else: + # Only load the images found in stack frames for the crashed threads + if options.crashed_only: + for thread in crash_log.threads: + if thread.did_crash(): + for ident in thread.idents: + images = crash_log.find_images_with_identifier(ident) + if images: + for image in images: + images_to_load.append(image) + else: + print 'error: can\'t find image for identifier "%s"' % ident + else: + for ident in crash_log.idents: + images = crash_log.find_images_with_identifier(ident) + if images: + for image in images: + images_to_load.append(image) + else: + print 'error: can\'t find image for identifier "%s"' % ident + + for image in images_to_load: + if image not in loaded_images: + err = image.add_module(target) + if err: + print err + else: + # print 'loaded %s' % image + loaded_images.append(image) + + if crash_log.backtraces: + for thread in crash_log.backtraces: + thread.dump_symbolicated(crash_log, options) + print + + for thread in crash_log.threads: + thread.dump_symbolicated(crash_log, options) + print + + +def CreateSymbolicateCrashLogOptions( + command_name, + description, + add_interactive_options): + usage = "usage: %prog [options] [FILE ...]" + option_parser = optparse.OptionParser( + description=description, prog='crashlog', usage=usage) + option_parser.add_option( + '--verbose', + '-v', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + option_parser.add_option( + '--debug', + '-g', + action='store_true', + dest='debug', + help='display verbose debug logging', + default=False) + option_parser.add_option( + '--load-all', + '-a', + action='store_true', + dest='load_all_images', + help='load all executable images, not just the images found in the crashed stack frames', + default=False) + option_parser.add_option( + '--images', + action='store_true', + dest='dump_image_list', + help='show image list', + default=False) + option_parser.add_option( + '--debug-delay', + type='int', + dest='debug_delay', + metavar='NSEC', + help='pause for NSEC seconds for debugger', + default=0) + option_parser.add_option( + '--crashed-only', + '-c', + action='store_true', + dest='crashed_only', + help='only symbolicate the crashed thread', + default=False) + option_parser.add_option( + '--disasm-depth', + '-d', + type='int', + dest='disassemble_depth', + help='set the depth in stack frames that should be disassembled (default is 1)', + default=1) + option_parser.add_option( + '--disasm-all', + '-D', + action='store_true', + dest='disassemble_all_threads', + help='enabled disassembly of frames on all threads (not just the crashed thread)', + default=False) + option_parser.add_option( + '--disasm-before', + '-B', + type='int', + dest='disassemble_before', + help='the number of instructions to disassemble before the frame PC', + default=4) + option_parser.add_option( + '--disasm-after', + '-A', + type='int', + dest='disassemble_after', + help='the number of instructions to disassemble after the frame PC', + default=4) + option_parser.add_option( + '--source-context', + '-C', + type='int', + metavar='NLINES', + dest='source_context', + help='show NLINES source lines of source context (default = 4)', + default=4) + option_parser.add_option( + '--source-frames', + type='int', + metavar='NFRAMES', + dest='source_frames', + help='show source for NFRAMES (default = 4)', + default=4) + option_parser.add_option( + '--source-all', + action='store_true', + dest='source_all', + help='show source for all threads, not just the crashed thread', + default=False) + if add_interactive_options: + option_parser.add_option( + '-i', + '--interactive', + action='store_true', + help='parse all crash logs and enter interactive mode', + default=False) + return option_parser + + +def SymbolicateCrashLogs(command_args): + description = '''Symbolicate one or more darwin crash log files to provide source file and line information, +inlined stack frames back to the concrete functions, and disassemble the location of the crash +for the first frame of the crashed thread. +If this script is imported into the LLDB command interpreter, a "crashlog" command will be added to the interpreter +for use at the LLDB command line. After a crash log has been parsed and symbolicated, a target will have been +created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows +you to explore the program as if it were stopped at the locations described in the crash log and functions can +be disassembled and lookups can be performed using the addresses found in the crash log.''' + option_parser = CreateSymbolicateCrashLogOptions( + 'crashlog', description, True) + try: + (options, args) = option_parser.parse_args(command_args) + except: + return + + if options.debug: + print 'command_args = %s' % command_args + print 'options', options + print 'args', args + + if options.debug_delay > 0: + print "Waiting %u seconds for debugger to attach..." % options.debug_delay + time.sleep(options.debug_delay) + error = lldb.SBError() + + if args: + if options.interactive: + interactive_crashlogs(options, args) + else: + for crash_log_file in args: + crash_log = CrashLog(crash_log_file) + SymbolicateCrashLog(crash_log, options) +if __name__ == '__main__': + # Create a new debugger instance + lldb.debugger = lldb.SBDebugger.Create() + SymbolicateCrashLogs(sys.argv[1:]) + lldb.SBDebugger.Destroy(lldb.debugger) +elif getattr(lldb, 'debugger', None): + lldb.debugger.HandleCommand( + 'command script add -f lldb.macosx.crashlog.Symbolicate crashlog') + lldb.debugger.HandleCommand( + 'command script add -f lldb.macosx.crashlog.save_crashlog save_crashlog') + print '"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help' diff --git a/examples/python/delta.py b/examples/python/delta.py new file mode 100755 index 000000000..1b192aceb --- /dev/null +++ b/examples/python/delta.py @@ -0,0 +1,134 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# This module will enable GDB remote packet logging when the +# 'start_gdb_log' command is called with a filename to log to. When the +# 'stop_gdb_log' command is called, it will disable the logging and +# print out statistics about how long commands took to execute and also +# will primnt ou +# Be sure to add the python path that points to the LLDB shared library. +# +# To use this in the embedded python interpreter using "lldb" just +# import it with the full path using the "command script import" +# command. This can be done from the LLDB command line: +# (lldb) command script import /path/to/gdbremote.py +# Or it can be added to your ~/.lldbinit file so this module is always +# available. +#---------------------------------------------------------------------- + +import commands +import optparse +import os +import shlex +import re +import tempfile + + +def start_gdb_log(debugger, command, result, dict): + '''Start logging GDB remote packets by enabling logging with timestamps and + thread safe logging. Follow a call to this function with a call to "stop_gdb_log" + in order to dump out the commands.''' + global log_file + if log_file: + result.PutCString( + 'error: logging is already in progress with file "%s"', + log_file) + else: + args_len = len(args) + if args_len == 0: + log_file = tempfile.mktemp() + elif len(args) == 1: + log_file = args[0] + + if log_file: + debugger.HandleCommand( + 'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % + log_file) + result.PutCString( + "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % + log_file) + return + + result.PutCString('error: invalid log file path') + result.PutCString(usage) + + +def parse_time_log(debugger, command, result, dict): + # Any commands whose names might be followed by more valid C identifier + # characters must be listed here + command_args = shlex.split(command) + parse_time_log_args(command_args) + + +def parse_time_log_args(command_args): + usage = "usage: parse_time_log [options] []" + description = '''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.''' + parser = optparse.OptionParser( + description=description, + prog='parse_time_log', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + try: + (options, args) = parser.parse_args(command_args) + except: + return + for log_file in args: + parse_log_file(log_file, options) + + +def parse_log_file(file, options): + '''Parse a log file that was contains timestamps. These logs are typically + generated using: + (lldb) log enable --threadsafe --timestamp --file .... + + This log file will contain timestamps and this function will then normalize + those packets to be relative to the first value timestamp that is found and + show delta times between log lines and also keep track of how long it takes + for GDB remote commands to make a send/receive round trip. This can be + handy when trying to figure out why some operation in the debugger is taking + a long time during a preset set of debugger commands.''' + + print '#----------------------------------------------------------------------' + print "# Log file: '%s'" % file + print '#----------------------------------------------------------------------' + + timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') + + base_time = 0.0 + last_time = 0.0 + file = open(file) + lines = file.read().splitlines() + for line in lines: + match = timestamp_regex.match(line) + if match: + curr_time = float(match.group(2)) + delta = 0.0 + if base_time: + delta = curr_time - last_time + else: + base_time = curr_time + + print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)) + last_time = curr_time + else: + print line + + +if __name__ == '__main__': + import sys + parse_time_log_args(sys.argv[1:]) + +else: + import lldb + if lldb.debugger: + # This initializer is being run from LLDB in the embedded command interpreter + # Add any commands contained in this module to LLDB + lldb.debugger.HandleCommand( + 'command script add -f delta.parse_time_log parse_time_log') + print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information' diff --git a/examples/python/diagnose_nsstring.py b/examples/python/diagnose_nsstring.py new file mode 100644 index 000000000..0404f714f --- /dev/null +++ b/examples/python/diagnose_nsstring.py @@ -0,0 +1,183 @@ +# This implements the "diagnose-nsstring" command, usually installed in the debug session like +# command script import lldb.diagnose +# it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the +# decisions it did and providing some useful context information that can +# be used for improving the formatter + +import lldb + + +def read_memory(process, location, size): + data = "" + error = lldb.SBError() + for x in range(0, size - 1): + byte = process.ReadUnsignedFromMemory(x + location, 1, error) + if error.fail: + data = data + "err%s" % "" if x == size - 2 else ":" + else: + try: + data = data + "0x%x" % byte + if byte == 0: + data = data + "(\\0)" + elif byte == 0xa: + data = data + "(\\a)" + elif byte == 0xb: + data = data + "(\\b)" + elif byte == 0xc: + data = data + "(\\c)" + elif byte == '\n': + data = data + "(\\n)" + else: + data = data + "(%s)" % chr(byte) + if x < size - 2: + data = data + ":" + except Exception as e: + print e + return data + + +def diagnose_nsstring_Command_Impl(debugger, command, result, internal_dict): + """ + A command to diagnose the LLDB NSString data formatter + invoke as + (lldb) diagnose-nsstring + e.g. + (lldb) diagnose-nsstring @"Hello world" + """ + target = debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetSelectedThread() + frame = thread.GetSelectedFrame() + if not target.IsValid() or not process.IsValid(): + return "unable to get target/process - cannot proceed" + options = lldb.SBExpressionOptions() + options.SetFetchDynamicValue() + error = lldb.SBError() + if frame.IsValid(): + nsstring = frame.EvaluateExpression(command, options) + else: + nsstring = target.EvaluateExpression(command, options) + print >>result, str(nsstring) + nsstring_address = nsstring.GetValueAsUnsigned(0) + if nsstring_address == 0: + return "unable to obtain the string - cannot proceed" + expression = "\ +struct $__lldb__notInlineMutable {\ + char* buffer;\ + signed long length;\ + signed long capacity;\ + unsigned int hasGap:1;\ + unsigned int isFixedCapacity:1;\ + unsigned int isExternalMutable:1;\ + unsigned int capacityProvidedExternally:1;\n\ +#if __LP64__\n\ + unsigned long desiredCapacity:60;\n\ +#else\n\ + unsigned long desiredCapacity:28;\n\ +#endif\n\ + void* contentsAllocator;\ +};\ +\ +struct $__lldb__CFString {\ + void* _cfisa;\ + uint8_t _cfinfo[4];\ + uint32_t _rc;\ + union {\ + struct __inline1 {\ + signed long length;\ + } inline1;\ + struct __notInlineImmutable1 {\ + char* buffer;\ + signed long length;\ + void* contentsDeallocator;\ + } notInlineImmutable1;\ + struct __notInlineImmutable2 {\ + char* buffer;\ + void* contentsDeallocator;\ + } notInlineImmutable2;\ + struct $__lldb__notInlineMutable notInlineMutable;\ + } variants;\ +};\ +" + + expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address + # print expression + dumped = target.EvaluateExpression(expression, options) + print >>result, str(dumped) + + little_endian = (target.byte_order == lldb.eByteOrderLittle) + ptr_size = target.addr_size + + info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex( + 0 if little_endian else 3).GetValueAsUnsigned(0) + is_mutable = (info_bits & 1) == 1 + is_inline = (info_bits & 0x60) == 0 + has_explicit_length = (info_bits & (1 | 4)) != 4 + is_unicode = (info_bits & 0x10) == 0x10 + is_special = ( + nsstring.GetDynamicValue( + lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2") + has_null = (info_bits & 8) == 8 + + print >>result, "\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \ + (info_bits, "yes" if is_mutable else "no", "yes" if is_inline else "no", "yes" if has_explicit_length else "no", "yes" if is_unicode else "no", "yes" if is_special else "no", "yes" if has_null else "no") + + explicit_length_offset = 0 + if not has_null and has_explicit_length and not is_special: + explicit_length_offset = 2 * ptr_size + if is_mutable and not is_inline: + explicit_length_offset = explicit_length_offset + ptr_size + elif is_inline: + pass + elif not is_inline and not is_mutable: + explicit_length_offset = explicit_length_offset + ptr_size + else: + explicit_length_offset = 0 + + if explicit_length_offset == 0: + print >>result, "There is no explicit length marker - skipping this step\n" + else: + explicit_length_offset = nsstring_address + explicit_length_offset + explicit_length = process.ReadUnsignedFromMemory( + explicit_length_offset, 4, error) + print >>result, "Explicit length location is at 0x%x - read value is %d\n" % ( + explicit_length_offset, explicit_length) + + if is_mutable: + location = 2 * ptr_size + nsstring_address + location = process.ReadPointerFromMemory(location, error) + elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable: + location = 3 * ptr_size + nsstring_address + elif is_unicode: + location = 2 * ptr_size + nsstring_address + if is_inline: + if not has_explicit_length: + print >>result, "Unicode & Inline & !Explicit is a new combo - no formula for it" + else: + location += ptr_size + else: + location = process.ReadPointerFromMemory(location, error) + elif is_special: + location = nsstring_address + ptr_size + 4 + elif is_inline: + location = 2 * ptr_size + nsstring_address + if not has_explicit_length: + location += 1 + else: + location = 2 * ptr_size + nsstring_address + location = process.ReadPointerFromMemory(location, error) + print >>result, "Expected data location: 0x%x\n" % (location) + print >>result, "1K of data around location: %s\n" % read_memory( + process, location, 1024) + print >>result, "5K of data around string pointer: %s\n" % read_memory( + process, nsstring_address, 1024 * 5) + + +def __lldb_init_module(debugger, internal_dict): + debugger.HandleCommand( + "command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" % + __name__) + print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.' + +__lldb_init_module(lldb.debugger, None) +__lldb_init_module = None diff --git a/examples/python/diagnose_unwind.py b/examples/python/diagnose_unwind.py new file mode 100644 index 000000000..b90372970 --- /dev/null +++ b/examples/python/diagnose_unwind.py @@ -0,0 +1,313 @@ +# This implements the "diagnose-unwind" command, usually installed +# in the debug session like +# command script import lldb.diagnose +# it is used when lldb's backtrace fails -- it collects and prints +# information about the stack frames, and tries an alternate unwind +# algorithm, that will help to understand why lldb's unwind algorithm +# did not succeed. + +import optparse +import lldb +import re +import shlex + +# Print the frame number, pc, frame pointer, module UUID and function name +# Returns the SBModule that contains the PC, if it could be found + + +def backtrace_print_frame(target, frame_num, addr, fp): + process = target.GetProcess() + addr_for_printing = addr + addr_width = process.GetAddressByteSize() * 2 + if frame_num > 0: + addr = addr - 1 + + sbaddr = lldb.SBAddress() + try: + sbaddr.SetLoadAddress(addr, target) + module_description = "" + if sbaddr.GetModule(): + module_filename = "" + module_uuid_str = sbaddr.GetModule().GetUUIDString() + if module_uuid_str is None: + module_uuid_str = "" + if sbaddr.GetModule().GetFileSpec(): + module_filename = sbaddr.GetModule().GetFileSpec().GetFilename() + if module_filename is None: + module_filename = "" + if module_uuid_str != "" or module_filename != "": + module_description = '%s %s' % ( + module_filename, module_uuid_str) + except Exception: + print '%2d: pc==0x%-*x fp==0x%-*x' % (frame_num, addr_width, addr_for_printing, addr_width, fp) + return + + sym_ctx = target.ResolveSymbolContextForAddress( + sbaddr, lldb.eSymbolContextEverything) + if sym_ctx.IsValid() and sym_ctx.GetSymbol().IsValid(): + function_start = sym_ctx.GetSymbol().GetStartAddress().GetLoadAddress(target) + offset = addr - function_start + print '%2d: pc==0x%-*x fp==0x%-*x %s %s + %d' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description, sym_ctx.GetSymbol().GetName(), offset) + else: + print '%2d: pc==0x%-*x fp==0x%-*x %s' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description) + return sbaddr.GetModule() + +# A simple stack walk algorithm that follows the frame chain. +# Returns a two-element list; the first element is a list of modules +# seen and the second element is a list of addresses seen during the backtrace. + + +def simple_backtrace(debugger): + target = debugger.GetSelectedTarget() + process = target.GetProcess() + cur_thread = process.GetSelectedThread() + + initial_fp = cur_thread.GetFrameAtIndex(0).GetFP() + + # If the pseudoreg "fp" isn't recognized, on arm hardcode to r7 which is + # correct for Darwin programs. + if initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm": + for reggroup in cur_thread.GetFrameAtIndex(1).registers: + if reggroup.GetName() == "General Purpose Registers": + for reg in reggroup: + if reg.GetName() == "r7": + initial_fp = int(reg.GetValue(), 16) + + module_list = [] + address_list = [cur_thread.GetFrameAtIndex(0).GetPC()] + this_module = backtrace_print_frame( + target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp) + print_stack_frame(process, initial_fp) + print "" + if this_module is not None: + module_list.append(this_module) + if cur_thread.GetNumFrames() < 2: + return [module_list, address_list] + + cur_fp = process.ReadPointerFromMemory(initial_fp, lldb.SBError()) + cur_pc = process.ReadPointerFromMemory( + initial_fp + process.GetAddressByteSize(), lldb.SBError()) + + frame_num = 1 + + while cur_pc != 0 and cur_fp != 0 and cur_pc != lldb.LLDB_INVALID_ADDRESS and cur_fp != lldb.LLDB_INVALID_ADDRESS: + address_list.append(cur_pc) + this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp) + print_stack_frame(process, cur_fp) + print "" + if this_module is not None: + module_list.append(this_module) + frame_num = frame_num + 1 + next_pc = 0 + next_fp = 0 + if target.triple[ + 0:6] == "x86_64" or target.triple[ + 0:4] == "i386" or target.triple[ + 0:3] == "arm": + error = lldb.SBError() + next_pc = process.ReadPointerFromMemory( + cur_fp + process.GetAddressByteSize(), error) + if not error.Success(): + next_pc = 0 + next_fp = process.ReadPointerFromMemory(cur_fp, error) + if not error.Success(): + next_fp = 0 + # Clear the 0th bit for arm frames - this indicates it is a thumb frame + if target.triple[0:3] == "arm" and (next_pc & 1) == 1: + next_pc = next_pc & ~1 + cur_pc = next_pc + cur_fp = next_fp + this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp) + print_stack_frame(process, cur_fp) + print "" + if this_module is not None: + module_list.append(this_module) + return [module_list, address_list] + + +def print_stack_frame(process, fp): + if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1: + return + addr_size = process.GetAddressByteSize() + addr = fp - (2 * addr_size) + i = 0 + outline = "Stack frame from $fp-%d: " % (2 * addr_size) + error = lldb.SBError() + try: + while i < 5 and error.Success(): + address = process.ReadPointerFromMemory( + addr + (i * addr_size), error) + outline += " 0x%x" % address + i += 1 + print outline + except Exception: + return + + +def diagnose_unwind(debugger, command, result, dict): + """ + Gather diagnostic information to help debug incorrect unwind (backtrace) + behavior in lldb. When there is a backtrace that doesn't look + correct, run this command with the correct thread selected and a + large amount of diagnostic information will be printed, it is likely + to be helpful when reporting the problem. + """ + + command_args = shlex.split(command) + parser = create_diagnose_unwind_options() + try: + (options, args) = parser.parse_args(command_args) + except: + return + target = debugger.GetSelectedTarget() + if target: + process = target.GetProcess() + if process: + thread = process.GetSelectedThread() + if thread: + lldb_versions_match = re.search( + r'[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?', + debugger.GetVersionString()) + lldb_version = 0 + lldb_minor = 0 + if len(lldb_versions_match.groups() + ) >= 1 and lldb_versions_match.groups()[0]: + lldb_major = int(lldb_versions_match.groups()[0]) + if len(lldb_versions_match.groups() + ) >= 5 and lldb_versions_match.groups()[4]: + lldb_minor = int(lldb_versions_match.groups()[4]) + + modules_seen = [] + addresses_seen = [] + + print 'LLDB version %s' % debugger.GetVersionString() + print 'Unwind diagnostics for thread %d' % thread.GetIndexID() + print "" + print "=============================================================================================" + print "" + print "OS plugin setting:" + debugger.HandleCommand( + "settings show target.process.python-os-plugin-path") + print "" + print "Live register context:" + thread.SetSelectedFrame(0) + debugger.HandleCommand("register read") + print "" + print "=============================================================================================" + print "" + print "lldb's unwind algorithm:" + print "" + frame_num = 0 + for frame in thread.frames: + if not frame.IsInlined(): + this_module = backtrace_print_frame( + target, frame_num, frame.GetPC(), frame.GetFP()) + print_stack_frame(process, frame.GetFP()) + print "" + if this_module is not None: + modules_seen.append(this_module) + addresses_seen.append(frame.GetPC()) + frame_num = frame_num + 1 + print "" + print "=============================================================================================" + print "" + print "Simple stack walk algorithm:" + print "" + (module_list, address_list) = simple_backtrace(debugger) + if module_list and module_list is not None: + modules_seen += module_list + if address_list and address_list is not None: + addresses_seen = set(addresses_seen) + addresses_seen.update(set(address_list)) + + print "" + print "=============================================================================================" + print "" + print "Modules seen in stack walks:" + print "" + modules_already_seen = set() + for module in modules_seen: + if module is not None and module.GetFileSpec().GetFilename() is not None: + if not module.GetFileSpec().GetFilename() in modules_already_seen: + debugger.HandleCommand( + 'image list %s' % + module.GetFileSpec().GetFilename()) + modules_already_seen.add( + module.GetFileSpec().GetFilename()) + + print "" + print "=============================================================================================" + print "" + print "Disassembly ofaddresses seen in stack walks:" + print "" + additional_addresses_to_disassemble = addresses_seen + for frame in thread.frames: + if not frame.IsInlined(): + print "--------------------------------------------------------------------------------------" + print "" + print "Disassembly of %s, frame %d, address 0x%x" % (frame.GetFunctionName(), frame.GetFrameID(), frame.GetPC()) + print "" + if target.triple[ + 0:6] == "x86_64" or target.triple[ + 0:4] == "i386": + debugger.HandleCommand( + 'disassemble -F att -a 0x%x' % frame.GetPC()) + else: + debugger.HandleCommand( + 'disassemble -a 0x%x' % + frame.GetPC()) + if frame.GetPC() in additional_addresses_to_disassemble: + additional_addresses_to_disassemble.remove( + frame.GetPC()) + + for address in list(additional_addresses_to_disassemble): + print "--------------------------------------------------------------------------------------" + print "" + print "Disassembly of 0x%x" % address + print "" + if target.triple[ + 0:6] == "x86_64" or target.triple[ + 0:4] == "i386": + debugger.HandleCommand( + 'disassemble -F att -a 0x%x' % address) + else: + debugger.HandleCommand('disassemble -a 0x%x' % address) + + print "" + print "=============================================================================================" + print "" + additional_addresses_to_show_unwind = addresses_seen + for frame in thread.frames: + if not frame.IsInlined(): + print "--------------------------------------------------------------------------------------" + print "" + print "Unwind instructions for %s, frame %d" % (frame.GetFunctionName(), frame.GetFrameID()) + print "" + debugger.HandleCommand( + 'image show-unwind -a "0x%x"' % frame.GetPC()) + if frame.GetPC() in additional_addresses_to_show_unwind: + additional_addresses_to_show_unwind.remove( + frame.GetPC()) + + for address in list(additional_addresses_to_show_unwind): + print "--------------------------------------------------------------------------------------" + print "" + print "Unwind instructions for 0x%x" % address + print "" + debugger.HandleCommand( + 'image show-unwind -a "0x%x"' % address) + + +def create_diagnose_unwind_options(): + usage = "usage: %prog" + description = '''Print diagnostic information about a thread backtrace which will help to debug unwind problems''' + parser = optparse.OptionParser( + description=description, + prog='diagnose_unwind', + usage=usage) + return parser + +lldb.debugger.HandleCommand( + 'command script add -f %s.diagnose_unwind diagnose-unwind' % + __name__) +print 'The "diagnose-unwind" command has been installed, type "help diagnose-unwind" for detailed help.' diff --git a/examples/python/dict_utils.py b/examples/python/dict_utils.py new file mode 100755 index 000000000..7cdd0ac6f --- /dev/null +++ b/examples/python/dict_utils.py @@ -0,0 +1,62 @@ + +class LookupDictionary(dict): + """ + a dictionary which can lookup value by key, or keys by value + """ + + def __init__(self, items=[]): + """items can be a list of pair_lists or a dictionary""" + dict.__init__(self, items) + + def get_keys_for_value(self, value, fail_value=None): + """find the key(s) as a list given a value""" + list_result = [item[0] for item in self.items() if item[1] == value] + if len(list_result) > 0: + return list_result + return fail_value + + def get_first_key_for_value(self, value, fail_value=None): + """return the first key of this dictionary given the value""" + list_result = [item[0] for item in self.items() if item[1] == value] + if len(list_result) > 0: + return list_result[0] + return fail_value + + def get_value(self, key, fail_value=None): + """find the value given a key""" + if key in self: + return self[key] + return fail_value + + +class Enum(LookupDictionary): + + def __init__(self, initial_value=0, items=[]): + """items can be a list of pair_lists or a dictionary""" + LookupDictionary.__init__(self, items) + self.value = initial_value + + def set_value(self, v): + v_typename = typeof(v).__name__ + if v_typename == 'str': + if str in self: + v = self[v] + else: + v = 0 + else: + self.value = v + + def get_enum_value(self): + return self.value + + def get_enum_name(self): + return self.__str__() + + def __str__(self): + s = self.get_first_key_for_value(self.value, None) + if s is None: + s = "%#8.8x" % self.value + return s + + def __repr__(self): + return self.__str__() diff --git a/examples/python/disasm-stress-test.py b/examples/python/disasm-stress-test.py new file mode 100755 index 000000000..2c20ffb92 --- /dev/null +++ b/examples/python/disasm-stress-test.py @@ -0,0 +1,230 @@ +#!/usr/bin/python + +import argparse +import datetime +import re +import subprocess +import sys +import time + +parser = argparse.ArgumentParser( + description="Run an exhaustive test of the LLDB disassembler for a specific architecture.") + +parser.add_argument( + '--arch', + required=True, + action='store', + help='The architecture whose disassembler is to be tested') +parser.add_argument( + '--bytes', + required=True, + action='store', + type=int, + help='The byte width of instructions for that architecture') +parser.add_argument( + '--random', + required=False, + action='store_true', + help='Enables non-sequential testing') +parser.add_argument( + '--start', + required=False, + action='store', + type=int, + help='The first instruction value to test') +parser.add_argument( + '--skip', + required=False, + action='store', + type=int, + help='The interval between instructions to test') +parser.add_argument( + '--log', + required=False, + action='store', + help='A log file to write the most recent instruction being tested') +parser.add_argument( + '--time', + required=False, + action='store_true', + help='Every 100,000 instructions, print an ETA to standard out') +parser.add_argument( + '--lldb', + required=False, + action='store', + help='The path to LLDB.framework, if LLDB should be overridden') + +arguments = sys.argv[1:] + +arg_ns = parser.parse_args(arguments) + + +def AddLLDBToSysPathOnMacOSX(): + def GetLLDBFrameworkPath(): + lldb_path = subprocess.check_output(["xcrun", "-find", "lldb"]) + re_result = re.match("(.*)/Developer/usr/bin/lldb", lldb_path) + if re_result is None: + return None + xcode_contents_path = re_result.group(1) + return xcode_contents_path + "/SharedFrameworks/LLDB.framework" + + lldb_framework_path = GetLLDBFrameworkPath() + + if lldb_framework_path is None: + print "Couldn't find LLDB.framework" + sys.exit(-1) + + sys.path.append(lldb_framework_path + "/Resources/Python") + +if arg_ns.lldb is None: + AddLLDBToSysPathOnMacOSX() +else: + sys.path.append(arg_ns.lldb + "/Resources/Python") + +import lldb + +debugger = lldb.SBDebugger.Create() + +if debugger.IsValid() == False: + print "Couldn't create an SBDebugger" + sys.exit(-1) + +target = debugger.CreateTargetWithFileAndArch(None, arg_ns.arch) + +if target.IsValid() == False: + print "Couldn't create an SBTarget for architecture " + arg_ns.arch + sys.exit(-1) + + +def ResetLogFile(log_file): + if log_file != sys.stdout: + log_file.seek(0) + + +def PrintByteArray(log_file, byte_array): + for byte in byte_array: + print >>log_file, hex(byte) + " ", + print >>log_file + + +class SequentialInstructionProvider: + + def __init__(self, byte_width, log_file, start=0, skip=1): + self.m_byte_width = byte_width + self.m_log_file = log_file + self.m_start = start + self.m_skip = skip + self.m_value = start + self.m_last = (1 << (byte_width * 8)) - 1 + + def PrintCurrentState(self, ret): + ResetLogFile(self.m_log_file) + print >>self.m_log_file, self.m_value + PrintByteArray(self.m_log_file, ret) + + def GetNextInstruction(self): + if self.m_value > self.m_last: + return None + ret = bytearray(self.m_byte_width) + for i in range(self.m_byte_width): + ret[self.m_byte_width - (i + 1)] = (self.m_value >> (i * 8)) & 255 + self.PrintCurrentState(ret) + self.m_value += self.m_skip + return ret + + def GetNumInstructions(self): + return (self.m_last - self.m_start) / self.m_skip + + def __iter__(self): + return self + + def next(self): + ret = self.GetNextInstruction() + if ret is None: + raise StopIteration + return ret + + +class RandomInstructionProvider: + + def __init__(self, byte_width, log_file): + self.m_byte_width = byte_width + self.m_log_file = log_file + self.m_random_file = open("/dev/random", 'r') + + def PrintCurrentState(self, ret): + ResetLogFile(self.m_log_file) + PrintByteArray(self.m_log_file, ret) + + def GetNextInstruction(self): + ret = bytearray(self.m_byte_width) + for i in range(self.m_byte_width): + ret[i] = self.m_random_file.read(1) + self.PrintCurrentState(ret) + return ret + + def __iter__(self): + return self + + def next(self): + ret = self.GetNextInstruction() + if ret is None: + raise StopIteration + return ret + +log_file = None + + +def GetProviderWithArguments(args): + global log_file + if args.log is not None: + log_file = open(args.log, 'w') + else: + log_file = sys.stdout + instruction_provider = None + if args.random: + instruction_provider = RandomInstructionProvider(args.bytes, log_file) + else: + start = 0 + skip = 1 + if args.start is not None: + start = args.start + if args.skip is not None: + skip = args.skip + instruction_provider = SequentialInstructionProvider( + args.bytes, log_file, start, skip) + return instruction_provider + +instruction_provider = GetProviderWithArguments(arg_ns) + +fake_address = lldb.SBAddress() + +actually_time = arg_ns.time and not arg_ns.random + +if actually_time: + num_instructions_logged = 0 + total_num_instructions = instruction_provider.GetNumInstructions() + start_time = time.time() + +for inst_bytes in instruction_provider: + if actually_time: + if (num_instructions_logged != 0) and ( + num_instructions_logged % 100000 == 0): + curr_time = time.time() + elapsed_time = curr_time - start_time + remaining_time = float( + total_num_instructions - num_instructions_logged) * ( + float(elapsed_time) / float(num_instructions_logged)) + print str(datetime.timedelta(seconds=remaining_time)) + num_instructions_logged = num_instructions_logged + 1 + inst_list = target.GetInstructions(fake_address, inst_bytes) + if not inst_list.IsValid(): + print >>log_file, "Invalid instruction list" + continue + inst = inst_list.GetInstructionAtIndex(0) + if not inst.IsValid(): + print >>log_file, "Invalid instruction" + continue + instr_output_stream = lldb.SBStream() + inst.GetDescription(instr_output_stream) + print >>log_file, instr_output_stream.GetData() diff --git a/examples/python/disasm.py b/examples/python/disasm.py new file mode 100755 index 000000000..af024a688 --- /dev/null +++ b/examples/python/disasm.py @@ -0,0 +1,126 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# On MacOSX csh, tcsh: +# setenv PYTHONPATH /Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python +# On MacOSX sh, bash: +# export PYTHONPATH=/Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python +#---------------------------------------------------------------------- + +import lldb +import os +import sys + + +def disassemble_instructions(insts): + for i in insts: + print i + + +def usage(): + print "Usage: disasm.py [-n name] executable-image" + print " By default, it breaks at and disassembles the 'main' function." + sys.exit(0) + +if len(sys.argv) == 2: + fname = 'main' + exe = sys.argv[1] +elif len(sys.argv) == 4: + if sys.argv[1] != '-n': + usage() + else: + fname = sys.argv[2] + exe = sys.argv[3] +else: + usage() + +# Create a new debugger instance +debugger = lldb.SBDebugger.Create() + +# When we step or continue, don't return from the function until the process +# stops. We do this by setting the async mode to false. +debugger.SetAsync(False) + +# Create a target from a file and arch +print "Creating a target for '%s'" % exe + +target = debugger.CreateTargetWithFileAndArch(exe, lldb.LLDB_ARCH_DEFAULT) + +if target: + # If the target is valid set a breakpoint at main + main_bp = target.BreakpointCreateByName( + fname, target.GetExecutable().GetFilename()) + + print main_bp + + # Launch the process. Since we specified synchronous mode, we won't return + # from this function until we hit the breakpoint at main + process = target.LaunchSimple(None, None, os.getcwd()) + + # Make sure the launch went ok + if process: + # Print some simple process info + state = process.GetState() + print process + if state == lldb.eStateStopped: + # Get the first thread + thread = process.GetThreadAtIndex(0) + if thread: + # Print some simple thread info + print thread + # Get the first frame + frame = thread.GetFrameAtIndex(0) + if frame: + # Print some simple frame info + print frame + function = frame.GetFunction() + # See if we have debug info (a function) + if function: + # We do have a function, print some info for the + # function + print function + # Now get all instructions for this function and print + # them + insts = function.GetInstructions(target) + disassemble_instructions(insts) + else: + # See if we have a symbol in the symbol table for where + # we stopped + symbol = frame.GetSymbol() + if symbol: + # We do have a symbol, print some info for the + # symbol + print symbol + # Now get all instructions for this symbol and + # print them + insts = symbol.GetInstructions(target) + disassemble_instructions(insts) + + registerList = frame.GetRegisters() + print "Frame registers (size of register set = %d):" % registerList.GetSize() + for value in registerList: + # print value + print "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()) + for child in value: + print "Name: ", child.GetName(), " Value: ", child.GetValue() + + print "Hit the breakpoint at main, enter to continue and wait for program to exit or 'Ctrl-D'/'quit' to terminate the program" + next = sys.stdin.readline() + if not next or next.rstrip('\n') == 'quit': + print "Terminating the inferior process..." + process.Kill() + else: + # Now continue to the program exit + process.Continue() + # When we return from the above function we will hopefully be at the + # program exit. Print out some process info + print process + elif state == lldb.eStateExited: + print "Didn't hit the breakpoint at main, program has exited..." + else: + print "Unexpected process state: %s, killing process..." % debugger.StateAsCString(state) + process.Kill() + + +lldb.SBDebugger.Terminate() diff --git a/examples/python/disassembly_mode.py b/examples/python/disassembly_mode.py new file mode 100644 index 000000000..19647cc65 --- /dev/null +++ b/examples/python/disassembly_mode.py @@ -0,0 +1,48 @@ +""" Adds the 'toggle-disassembly' command to switch you into a disassembly only mode """ +import lldb + +class DisassemblyMode: + def __init__(self, debugger, unused): + self.dbg = debugger + self.interp = debugger.GetCommandInterpreter() + self.store_state() + self.mode_off = True + + def store_state(self): + self.dis_count = self.get_string_value("stop-disassembly-count") + self.dis_display = self.get_string_value("stop-disassembly-display") + self.before_count = self.get_string_value("stop-line-count-before") + self.after_count = self.get_string_value("stop-line-count-after") + + def get_string_value(self, setting): + result = lldb.SBCommandReturnObject() + self.interp.HandleCommand("settings show " + setting, result) + value = result.GetOutput().split(" = ")[1].rstrip("\n") + return value + + def set_value(self, setting, value): + result = lldb.SBCommandReturnObject() + self.interp.HandleCommand("settings set " + setting + " " + value, result) + + def __call__(self, debugger, command, exe_ctx, result): + if self.mode_off: + self.mode_off = False + self.store_state() + self.set_value("stop-disassembly-display","always") + self.set_value("stop-disassembly-count", "8") + self.set_value("stop-line-count-before", "0") + self.set_value("stop-line-count-after", "0") + result.AppendMessage("Disassembly mode on.") + else: + self.mode_off = True + self.set_value("stop-disassembly-display",self.dis_display) + self.set_value("stop-disassembly-count", self.dis_count) + self.set_value("stop-line-count-before", self.before_count) + self.set_value("stop-line-count-after", self.after_count) + result.AppendMessage("Disassembly mode off.") + + def get_short_help(self): + return "Toggles between a disassembly only mode and normal source mode\n" + +def __lldb_init_module(debugger, unused): + debugger.HandleCommand("command script add -c disassembly_mode.DisassemblyMode toggle-disassembly") diff --git a/examples/python/file_extract.py b/examples/python/file_extract.py new file mode 100755 index 000000000..7a617e911 --- /dev/null +++ b/examples/python/file_extract.py @@ -0,0 +1,226 @@ +#! /usr/bin/env python + +import string +import struct +import sys + + +class FileExtract: + '''Decode binary data from a file''' + + def __init__(self, f, b='='): + '''Initialize with an open binary file and optional byte order''' + + self.file = f + self.byte_order = b + self.offsets = list() + + def set_byte_order(self, b): + '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="''' + if b == 'big': + self.byte_order = '>' + elif b == 'little': + self.byte_order = '<' + elif b == 'swap': + # swap what ever the current byte order is + self.byte_order = swap_unpack_char() + elif b == 'native': + self.byte_order = '=' + elif b == '<' or b == '>' or b == '@' or b == '=': + self.byte_order = b + else: + print "error: invalid byte order specified: '%s'" % b + + def is_in_memory(self): + return False + + def seek(self, offset, whence=0): + if self.file: + return self.file.seek(offset, whence) + raise ValueError + + def tell(self): + if self.file: + return self.file.tell() + raise ValueError + + def read_size(self, byte_size): + s = self.file.read(byte_size) + if len(s) != byte_size: + return None + return s + + def push_offset_and_seek(self, offset): + '''Push the current file offset and seek to "offset"''' + self.offsets.append(self.file.tell()) + self.file.seek(offset, 0) + + def pop_offset_and_seek(self): + '''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets''' + if len(self.offsets) > 0: + self.file.seek(self.offsets.pop()) + + def get_sint8(self, fail_value=0): + '''Extract a single int8_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(1) + if s: + v, = struct.unpack(self.byte_order + 'b', s) + return v + else: + return fail_value + + def get_uint8(self, fail_value=0): + '''Extract a single uint8_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(1) + if s: + v, = struct.unpack(self.byte_order + 'B', s) + return v + else: + return fail_value + + def get_sint16(self, fail_value=0): + '''Extract a single int16_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(2) + if s: + v, = struct.unpack(self.byte_order + 'h', s) + return v + else: + return fail_value + + def get_uint16(self, fail_value=0): + '''Extract a single uint16_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(2) + if s: + v, = struct.unpack(self.byte_order + 'H', s) + return v + else: + return fail_value + + def get_sint32(self, fail_value=0): + '''Extract a single int32_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(4) + if s: + v, = struct.unpack(self.byte_order + 'i', s) + return v + else: + return fail_value + + def get_uint32(self, fail_value=0): + '''Extract a single uint32_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(4) + if s: + v, = struct.unpack(self.byte_order + 'I', s) + return v + else: + return fail_value + + def get_sint64(self, fail_value=0): + '''Extract a single int64_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(8) + if s: + v, = struct.unpack(self.byte_order + 'q', s) + return v + else: + return fail_value + + def get_uint64(self, fail_value=0): + '''Extract a single uint64_t from the binary file at the current file position, returns a single integer''' + s = self.read_size(8) + if s: + v, = struct.unpack(self.byte_order + 'Q', s) + return v + else: + return fail_value + + def get_fixed_length_c_string( + self, + n, + fail_value='', + isprint_only_with_space_padding=False): + '''Extract a single fixed length C string from the binary file at the current file position, returns a single C string''' + s = self.read_size(n) + if s: + cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s) + # Strip trialing NULLs + cstr = string.strip(cstr, "\0") + if isprint_only_with_space_padding: + for c in cstr: + if c in string.printable or ord(c) == 0: + continue + return fail_value + return cstr + else: + return fail_value + + def get_c_string(self): + '''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string''' + cstr = '' + byte = self.get_uint8() + while byte != 0: + cstr += "%c" % byte + byte = self.get_uint8() + return cstr + + def get_n_sint8(self, n, fail_value=0): + '''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'b', s) + else: + return (fail_value,) * n + + def get_n_uint8(self, n, fail_value=0): + '''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'B', s) + else: + return (fail_value,) * n + + def get_n_sint16(self, n, fail_value=0): + '''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(2 * n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'h', s) + else: + return (fail_value,) * n + + def get_n_uint16(self, n, fail_value=0): + '''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(2 * n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'H', s) + else: + return (fail_value,) * n + + def get_n_sint32(self, n, fail_value=0): + '''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(4 * n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'i', s) + else: + return (fail_value,) * n + + def get_n_uint32(self, n, fail_value=0): + '''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(4 * n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'I', s) + else: + return (fail_value,) * n + + def get_n_sint64(self, n, fail_value=0): + '''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(8 * n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'q', s) + else: + return (fail_value,) * n + + def get_n_uint64(self, n, fail_value=0): + '''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers''' + s = self.read_size(8 * n) + if s: + return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s) + else: + return (fail_value,) * n diff --git a/examples/python/gdb_disassemble.py b/examples/python/gdb_disassemble.py new file mode 100755 index 000000000..2590aba8c --- /dev/null +++ b/examples/python/gdb_disassemble.py @@ -0,0 +1,26 @@ +import lldb + + +def disassemble(debugger, command, result, dict): + if lldb.frame.function: + instructions = lldb.frame.function.instructions + start_addr = lldb.frame.function.addr.load_addr + name = lldb.frame.function.name + elif lldb.frame.symbol: + instructions = lldb.frame.symbol.instructions + start_addr = lldb.frame.symbol.addr.load_addr + name = lldb.frame.symbol.name + + for inst in instructions: + inst_addr = inst.addr.load_addr + inst_offset = inst_addr - start_addr + comment = inst.comment + if comment: + print "<%s + %-4u> 0x%x %8s %s ; %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands, comment) + else: + print "<%s + %-4u> 0x%x %8s %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands) + +# Install the command when the module gets imported +lldb.debugger.HandleCommand( + 'command script add -f gdb_disassemble.disassemble gdb-disassemble') +print 'Installed "gdb-disassemble" command for disassembly' diff --git a/examples/python/gdbremote.py b/examples/python/gdbremote.py new file mode 100755 index 000000000..a6ff3f597 --- /dev/null +++ b/examples/python/gdbremote.py @@ -0,0 +1,1558 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# This module will enable GDB remote packet logging when the +# 'start_gdb_log' command is called with a filename to log to. When the +# 'stop_gdb_log' command is called, it will disable the logging and +# print out statistics about how long commands took to execute and also +# will primnt ou +# Be sure to add the python path that points to the LLDB shared library. +# +# To use this in the embedded python interpreter using "lldb" just +# import it with the full path using the "command script import" +# command. This can be done from the LLDB command line: +# (lldb) command script import /path/to/gdbremote.py +# Or it can be added to your ~/.lldbinit file so this module is always +# available. +#---------------------------------------------------------------------- + +import binascii +import commands +import json +import math +import optparse +import os +import re +import shlex +import string +import sys +import tempfile +import xml.etree.ElementTree as ET + +#---------------------------------------------------------------------- +# Global variables +#---------------------------------------------------------------------- +g_log_file = '' +g_byte_order = 'little' +g_number_regex = re.compile('^(0x[0-9a-fA-F]+|[0-9]+)') +g_thread_id_regex = re.compile('^(-1|[0-9a-fA-F]+|0)') + + +class TerminalColors: + '''Simple terminal colors class''' + + def __init__(self, enabled=True): + # TODO: discover terminal type from "file" and disable if + # it can't handle the color codes + self.enabled = enabled + + def reset(self): + '''Reset all terminal colors and formatting.''' + if self.enabled: + return "\x1b[0m" + return '' + + def bold(self, on=True): + '''Enable or disable bold depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[1m" + else: + return "\x1b[22m" + return '' + + def italics(self, on=True): + '''Enable or disable italics depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[3m" + else: + return "\x1b[23m" + return '' + + def underline(self, on=True): + '''Enable or disable underline depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[4m" + else: + return "\x1b[24m" + return '' + + def inverse(self, on=True): + '''Enable or disable inverse depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[7m" + else: + return "\x1b[27m" + return '' + + def strike(self, on=True): + '''Enable or disable strike through depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[9m" + else: + return "\x1b[29m" + return '' + + def black(self, fg=True): + '''Set the foreground or background color to black. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[30m" + else: + return "\x1b[40m" + return '' + + def red(self, fg=True): + '''Set the foreground or background color to red. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[31m" + else: + return "\x1b[41m" + return '' + + def green(self, fg=True): + '''Set the foreground or background color to green. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[32m" + else: + return "\x1b[42m" + return '' + + def yellow(self, fg=True): + '''Set the foreground or background color to yellow. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[33m" + else: + return "\x1b[43m" + return '' + + def blue(self, fg=True): + '''Set the foreground or background color to blue. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[34m" + else: + return "\x1b[44m" + return '' + + def magenta(self, fg=True): + '''Set the foreground or background color to magenta. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[35m" + else: + return "\x1b[45m" + return '' + + def cyan(self, fg=True): + '''Set the foreground or background color to cyan. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[36m" + else: + return "\x1b[46m" + return '' + + def white(self, fg=True): + '''Set the foreground or background color to white. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[37m" + else: + return "\x1b[47m" + return '' + + def default(self, fg=True): + '''Set the foreground or background color to the default. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[39m" + else: + return "\x1b[49m" + return '' + + +def start_gdb_log(debugger, command, result, dict): + '''Start logging GDB remote packets by enabling logging with timestamps and + thread safe logging. Follow a call to this function with a call to "stop_gdb_log" + in order to dump out the commands.''' + global g_log_file + command_args = shlex.split(command) + usage = "usage: start_gdb_log [options] []" + description = '''The command enables GDB remote packet logging with timestamps. The packets will be logged to if supplied, or a temporary file will be used. Logging stops when stop_gdb_log is called and the packet times will + be aggregated and displayed.''' + parser = optparse.OptionParser( + description=description, + prog='start_gdb_log', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + try: + (options, args) = parser.parse_args(command_args) + except: + return + + if g_log_file: + result.PutCString( + 'error: logging is already in progress with file "%s"' % + g_log_file) + else: + args_len = len(args) + if args_len == 0: + g_log_file = tempfile.mktemp() + elif len(args) == 1: + g_log_file = args[0] + + if g_log_file: + debugger.HandleCommand( + 'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % + g_log_file) + result.PutCString( + "GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % + g_log_file) + return + + result.PutCString('error: invalid log file path') + result.PutCString(usage) + + +def stop_gdb_log(debugger, command, result, dict): + '''Stop logging GDB remote packets to the file that was specified in a call + to "start_gdb_log" and normalize the timestamps to be relative to the first + timestamp in the log file. Also print out statistics for how long each + command took to allow performance bottlenecks to be determined.''' + global g_log_file + # Any commands whose names might be followed by more valid C identifier + # characters must be listed here + command_args = shlex.split(command) + usage = "usage: stop_gdb_log [options]" + description = '''The command stops a previously enabled GDB remote packet logging command. Packet logging must have been previously enabled with a call to start_gdb_log.''' + parser = optparse.OptionParser( + description=description, + prog='stop_gdb_log', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + parser.add_option( + '-q', + '--quiet', + action='store_true', + dest='quiet', + help='display verbose debug info', + default=False) + parser.add_option( + '-C', + '--color', + action='store_true', + dest='color', + help='add terminal colors', + default=False) + parser.add_option( + '-c', + '--sort-by-count', + action='store_true', + dest='sort_count', + help='display verbose debug info', + default=False) + parser.add_option( + '-s', + '--symbolicate', + action='store_true', + dest='symbolicate', + help='symbolicate addresses in log using current "lldb.target"', + default=False) + try: + (options, args) = parser.parse_args(command_args) + except: + return + options.colors = TerminalColors(options.color) + options.symbolicator = None + if options.symbolicate: + if lldb.target: + import lldb.utils.symbolication + options.symbolicator = lldb.utils.symbolication.Symbolicator() + options.symbolicator.target = lldb.target + else: + print "error: can't symbolicate without a target" + + if not g_log_file: + result.PutCString( + 'error: logging must have been previously enabled with a call to "stop_gdb_log"') + elif os.path.exists(g_log_file): + if len(args) == 0: + debugger.HandleCommand('log disable gdb-remote packets') + result.PutCString( + "GDB packet logging disabled. Logged packets are in '%s'" % + g_log_file) + parse_gdb_log_file(g_log_file, options) + else: + result.PutCString(usage) + else: + print 'error: the GDB packet log file "%s" does not exist' % g_log_file + + +def is_hex_byte(str): + if len(str) == 2: + return str[0] in string.hexdigits and str[1] in string.hexdigits + return False + +def get_hex_string_if_all_printable(str): + try: + s = binascii.unhexlify(str) + if all(c in string.printable for c in s): + return s + except TypeError: + pass + return None + +# global register info list +g_register_infos = list() +g_max_register_info_name_len = 0 + + +class RegisterInfo: + """Class that represents register information""" + + def __init__(self, kvp): + self.info = dict() + for kv in kvp: + key = kv[0] + value = kv[1] + self.info[key] = value + + def name(self): + '''Get the name of the register.''' + if self.info and 'name' in self.info: + return self.info['name'] + return None + + def bit_size(self): + '''Get the size in bits of the register.''' + if self.info and 'bitsize' in self.info: + return int(self.info['bitsize']) + return 0 + + def byte_size(self): + '''Get the size in bytes of the register.''' + return self.bit_size() / 8 + + def get_value_from_hex_string(self, hex_str): + '''Dump the register value given a native byte order encoded hex ASCII byte string.''' + encoding = self.info['encoding'] + bit_size = self.bit_size() + packet = Packet(hex_str) + if encoding == 'uint': + uval = packet.get_hex_uint(g_byte_order) + if bit_size == 8: + return '0x%2.2x' % (uval) + elif bit_size == 16: + return '0x%4.4x' % (uval) + elif bit_size == 32: + return '0x%8.8x' % (uval) + elif bit_size == 64: + return '0x%16.16x' % (uval) + bytes = list() + uval = packet.get_hex_uint8() + while uval is not None: + bytes.append(uval) + uval = packet.get_hex_uint8() + value_str = '0x' + if g_byte_order == 'little': + bytes.reverse() + for byte in bytes: + value_str += '%2.2x' % byte + return '%s' % (value_str) + + def __str__(self): + '''Dump the register info key/value pairs''' + s = '' + for key in self.info.keys(): + if s: + s += ', ' + s += "%s=%s " % (key, self.info[key]) + return s + + +class Packet: + """Class that represents a packet that contains string data""" + + def __init__(self, packet_str): + self.str = packet_str + + def peek_char(self): + ch = 0 + if self.str: + ch = self.str[0] + return ch + + def get_char(self): + ch = 0 + if self.str: + ch = self.str[0] + self.str = self.str[1:] + return ch + + def skip_exact_string(self, s): + if self.str and self.str.startswith(s): + self.str = self.str[len(s):] + return True + else: + return False + + def get_thread_id(self, fail_value=-1): + match = g_number_regex.match(self.str) + if match: + number_str = match.group(1) + self.str = self.str[len(number_str):] + return int(number_str, 0) + else: + return fail_value + + def get_hex_uint8(self): + if self.str and len(self.str) >= 2 and self.str[ + 0] in string.hexdigits and self.str[1] in string.hexdigits: + uval = int(self.str[0:2], 16) + self.str = self.str[2:] + return uval + return None + + def get_hex_uint16(self, byte_order): + uval = 0 + if byte_order == 'big': + uval |= self.get_hex_uint8() << 8 + uval |= self.get_hex_uint8() + else: + uval |= self.get_hex_uint8() + uval |= self.get_hex_uint8() << 8 + return uval + + def get_hex_uint32(self, byte_order): + uval = 0 + if byte_order == 'big': + uval |= self.get_hex_uint8() << 24 + uval |= self.get_hex_uint8() << 16 + uval |= self.get_hex_uint8() << 8 + uval |= self.get_hex_uint8() + else: + uval |= self.get_hex_uint8() + uval |= self.get_hex_uint8() << 8 + uval |= self.get_hex_uint8() << 16 + uval |= self.get_hex_uint8() << 24 + return uval + + def get_hex_uint64(self, byte_order): + uval = 0 + if byte_order == 'big': + uval |= self.get_hex_uint8() << 56 + uval |= self.get_hex_uint8() << 48 + uval |= self.get_hex_uint8() << 40 + uval |= self.get_hex_uint8() << 32 + uval |= self.get_hex_uint8() << 24 + uval |= self.get_hex_uint8() << 16 + uval |= self.get_hex_uint8() << 8 + uval |= self.get_hex_uint8() + else: + uval |= self.get_hex_uint8() + uval |= self.get_hex_uint8() << 8 + uval |= self.get_hex_uint8() << 16 + uval |= self.get_hex_uint8() << 24 + uval |= self.get_hex_uint8() << 32 + uval |= self.get_hex_uint8() << 40 + uval |= self.get_hex_uint8() << 48 + uval |= self.get_hex_uint8() << 56 + return uval + + def get_number(self, fail_value=-1): + '''Get a number from the packet. The number must be in big endian format and should be parsed + according to its prefix (starts with "0x" means hex, starts with "0" means octal, starts with + [1-9] means decimal, etc)''' + match = g_number_regex.match(self.str) + if match: + number_str = match.group(1) + self.str = self.str[len(number_str):] + return int(number_str, 0) + else: + return fail_value + + def get_hex_ascii_str(self, n=0): + hex_chars = self.get_hex_chars(n) + if hex_chars: + return binascii.unhexlify(hex_chars) + else: + return None + + def get_hex_chars(self, n=0): + str_len = len(self.str) + if n == 0: + # n was zero, so we need to determine all hex chars and + # stop when we hit the end of the string of a non-hex character + while n < str_len and self.str[n] in string.hexdigits: + n = n + 1 + else: + if n > str_len: + return None # Not enough chars + # Verify all chars are hex if a length was specified + for i in range(n): + if self.str[i] not in string.hexdigits: + return None # Not all hex digits + if n == 0: + return None + hex_str = self.str[0:n] + self.str = self.str[n:] + return hex_str + + def get_hex_uint(self, byte_order, n=0): + if byte_order == 'big': + hex_str = self.get_hex_chars(n) + if hex_str is None: + return None + return int(hex_str, 16) + else: + uval = self.get_hex_uint8() + if uval is None: + return None + uval_result = 0 + shift = 0 + while uval is not None: + uval_result |= (uval << shift) + shift += 8 + uval = self.get_hex_uint8() + return uval_result + + def get_key_value_pairs(self): + kvp = list() + if ';' in self.str: + key_value_pairs = string.split(self.str, ';') + for key_value_pair in key_value_pairs: + if len(key_value_pair): + kvp.append(string.split(key_value_pair, ':')) + return kvp + + def split(self, ch): + return string.split(self.str, ch) + + def split_hex(self, ch, byte_order): + hex_values = list() + strings = string.split(self.str, ch) + for str in strings: + hex_values.append(Packet(str).get_hex_uint(byte_order)) + return hex_values + + def __str__(self): + return self.str + + def __len__(self): + return len(self.str) + +g_thread_suffix_regex = re.compile(';thread:([0-9a-fA-F]+);') + + +def get_thread_from_thread_suffix(str): + if str: + match = g_thread_suffix_regex.match(str) + if match: + return int(match.group(1), 16) + return None + + +def cmd_qThreadStopInfo(options, cmd, args): + packet = Packet(args) + tid = packet.get_hex_uint('big') + print "get_thread_stop_info (tid = 0x%x)" % (tid) + + +def cmd_stop_reply(options, cmd, args): + print "get_last_stop_info()" + return False + + +def rsp_stop_reply(options, cmd, cmd_args, rsp): + global g_byte_order + packet = Packet(rsp) + stop_type = packet.get_char() + if stop_type == 'T' or stop_type == 'S': + signo = packet.get_hex_uint8() + key_value_pairs = packet.get_key_value_pairs() + for key_value_pair in key_value_pairs: + key = key_value_pair[0] + if is_hex_byte(key): + reg_num = Packet(key).get_hex_uint8() + if reg_num < len(g_register_infos): + reg_info = g_register_infos[reg_num] + key_value_pair[0] = reg_info.name() + key_value_pair[1] = reg_info.get_value_from_hex_string( + key_value_pair[1]) + elif key == 'jthreads' or key == 'jstopinfo': + key_value_pair[1] = binascii.unhexlify(key_value_pair[1]) + key_value_pairs.insert(0, ['signal', signo]) + print 'stop_reply():' + dump_key_value_pairs(key_value_pairs) + elif stop_type == 'W': + exit_status = packet.get_hex_uint8() + print 'stop_reply(): exit (status=%i)' % exit_status + elif stop_type == 'O': + print 'stop_reply(): stdout = "%s"' % packet.str + + +def cmd_unknown_packet(options, cmd, args): + if args: + print "cmd: %s, args: %s", cmd, args + else: + print "cmd: %s", cmd + return False + + +def cmd_qSymbol(options, cmd, args): + if args == ':': + print 'ready to serve symbols' + else: + packet = Packet(args) + symbol_addr = packet.get_hex_uint('big') + if symbol_addr is None: + if packet.skip_exact_string(':'): + symbol_name = packet.get_hex_ascii_str() + print 'lookup_symbol("%s") -> symbol not available yet' % (symbol_name) + else: + print 'error: bad command format' + else: + if packet.skip_exact_string(':'): + symbol_name = packet.get_hex_ascii_str() + print 'lookup_symbol("%s") -> 0x%x' % (symbol_name, symbol_addr) + else: + print 'error: bad command format' + +def cmd_QSetWithHexString(options, cmd, args): + print '%s("%s")' % (cmd[:-1], binascii.unhexlify(args)) + +def cmd_QSetWithString(options, cmd, args): + print '%s("%s")' % (cmd[:-1], args) + +def cmd_QSetWithUnsigned(options, cmd, args): + print '%s(%i)' % (cmd[:-1], int(args)) + +def rsp_qSymbol(options, cmd, cmd_args, rsp): + if len(rsp) == 0: + print "Unsupported" + else: + if rsp == "OK": + print "No more symbols to lookup" + else: + packet = Packet(rsp) + if packet.skip_exact_string("qSymbol:"): + symbol_name = packet.get_hex_ascii_str() + print 'lookup_symbol("%s")' % (symbol_name) + else: + print 'error: response string should start with "qSymbol:": respnse is "%s"' % (rsp) + + +def cmd_qXfer(options, cmd, args): + # $qXfer:features:read:target.xml:0,1ffff#14 + print "read target special data %s" % (args) + return True + + +def rsp_qXfer(options, cmd, cmd_args, rsp): + data = string.split(cmd_args, ':') + if data[0] == 'features': + if data[1] == 'read': + filename, extension = os.path.splitext(data[2]) + if extension == '.xml': + response = Packet(rsp) + xml_string = response.get_hex_ascii_str() + ch = xml_string[0] + if ch == 'l': + xml_string = xml_string[1:] + xml_root = ET.fromstring(xml_string) + for reg_element in xml_root.findall("./feature/reg"): + if not 'value_regnums' in reg_element.attrib: + reg_info = RegisterInfo([]) + if 'name' in reg_element.attrib: + reg_info.info[ + 'name'] = reg_element.attrib['name'] + else: + reg_info.info['name'] = 'unspecified' + if 'encoding' in reg_element.attrib: + reg_info.info['encoding'] = reg_element.attrib[ + 'encoding'] + else: + reg_info.info['encoding'] = 'uint' + if 'offset' in reg_element.attrib: + reg_info.info[ + 'offset'] = reg_element.attrib['offset'] + if 'bitsize' in reg_element.attrib: + reg_info.info[ + 'bitsize'] = reg_element.attrib['bitsize'] + g_register_infos.append(reg_info) + print 'XML for "%s":' % (data[2]) + ET.dump(xml_root) + + +def cmd_A(options, cmd, args): + print 'launch process:' + packet = Packet(args) + while True: + arg_len = packet.get_number() + if arg_len == -1: + break + if not packet.skip_exact_string(','): + break + arg_idx = packet.get_number() + if arg_idx == -1: + break + if not packet.skip_exact_string(','): + break + arg_value = packet.get_hex_ascii_str(arg_len) + print 'argv[%u] = "%s"' % (arg_idx, arg_value) + + +def cmd_qC(options, cmd, args): + print "query_current_thread_id()" + + +def rsp_qC(options, cmd, cmd_args, rsp): + packet = Packet(rsp) + if packet.skip_exact_string("QC"): + tid = packet.get_thread_id() + print "current_thread_id = %#x" % (tid) + else: + print "current_thread_id = old thread ID" + + +def cmd_query_packet(options, cmd, args): + if args: + print "%s%s" % (cmd, args) + else: + print "%s" % (cmd) + return False + + +def rsp_ok_error(rsp): + print "rsp: ", rsp + + +def rsp_ok_means_supported(options, cmd, cmd_args, rsp): + if rsp == 'OK': + print "%s%s is supported" % (cmd, cmd_args) + elif rsp == '': + print "%s%s is not supported" % (cmd, cmd_args) + else: + print "%s%s -> %s" % (cmd, cmd_args, rsp) + + +def rsp_ok_means_success(options, cmd, cmd_args, rsp): + if rsp == 'OK': + print "success" + elif rsp == '': + print "%s%s is not supported" % (cmd, cmd_args) + else: + print "%s%s -> %s" % (cmd, cmd_args, rsp) + + +def dump_key_value_pairs(key_value_pairs): + max_key_len = 0 + for key_value_pair in key_value_pairs: + key_len = len(key_value_pair[0]) + if max_key_len < key_len: + max_key_len = key_len + for key_value_pair in key_value_pairs: + key = key_value_pair[0] + value = key_value_pair[1] + unhex_value = get_hex_string_if_all_printable(value) + if unhex_value: + print "%*s = %s (%s)" % (max_key_len, key, value, unhex_value) + else: + print "%*s = %s" % (max_key_len, key, value) + + +def rsp_dump_key_value_pairs(options, cmd, cmd_args, rsp): + if rsp: + print '%s response:' % (cmd) + packet = Packet(rsp) + key_value_pairs = packet.get_key_value_pairs() + dump_key_value_pairs(key_value_pairs) + else: + print "not supported" + + +def cmd_c(options, cmd, args): + print "continue()" + return False + + +def cmd_s(options, cmd, args): + print "step()" + return False + + +def cmd_vCont(options, cmd, args): + if args == '?': + print "%s: get supported extended continue modes" % (cmd) + else: + got_other_threads = 0 + s = '' + for thread_action in string.split(args[1:], ';'): + (short_action, thread) = string.split(thread_action, ':') + tid = int(thread, 16) + if short_action == 'c': + action = 'continue' + elif short_action == 's': + action = 'step' + elif short_action[0] == 'C': + action = 'continue with signal 0x%s' % (short_action[1:]) + elif short_action == 'S': + action = 'step with signal 0x%s' % (short_action[1:]) + else: + action = short_action + if s: + s += ', ' + if tid == -1: + got_other_threads = 1 + s += 'other-threads:' + else: + s += 'thread 0x%4.4x: %s' % (tid, action) + if got_other_threads: + print "extended_continue (%s)" % (s) + else: + print "extended_continue (%s, other-threads: suspend)" % (s) + return False + + +def rsp_vCont(options, cmd, cmd_args, rsp): + if cmd_args == '?': + # Skip the leading 'vCont;' + rsp = rsp[6:] + modes = string.split(rsp, ';') + s = "%s: supported extended continue modes include: " % (cmd) + + for i, mode in enumerate(modes): + if i: + s += ', ' + if mode == 'c': + s += 'continue' + elif mode == 'C': + s += 'continue with signal' + elif mode == 's': + s += 'step' + elif mode == 'S': + s += 'step with signal' + else: + s += 'unrecognized vCont mode: ', mode + print s + elif rsp: + if rsp[0] == 'T' or rsp[0] == 'S' or rsp[0] == 'W' or rsp[0] == 'X': + rsp_stop_reply(options, cmd, cmd_args, rsp) + return + if rsp[0] == 'O': + print "stdout: %s" % (rsp) + return + else: + print "not supported (cmd = '%s', args = '%s', rsp = '%s')" % (cmd, cmd_args, rsp) + + +def cmd_vAttach(options, cmd, args): + (extra_command, args) = string.split(args, ';') + if extra_command: + print "%s%s(%s)" % (cmd, extra_command, args) + else: + print "attach(pid = %u)" % int(args, 16) + return False + + +def cmd_qRegisterInfo(options, cmd, args): + print 'query_register_info(reg_num=%i)' % (int(args, 16)) + return False + + +def rsp_qRegisterInfo(options, cmd, cmd_args, rsp): + global g_max_register_info_name_len + print 'query_register_info(reg_num=%i):' % (int(cmd_args, 16)), + if len(rsp) == 3 and rsp[0] == 'E': + g_max_register_info_name_len = 0 + for reg_info in g_register_infos: + name_len = len(reg_info.name()) + if g_max_register_info_name_len < name_len: + g_max_register_info_name_len = name_len + print' DONE' + else: + packet = Packet(rsp) + reg_info = RegisterInfo(packet.get_key_value_pairs()) + g_register_infos.append(reg_info) + print reg_info + return False + + +def cmd_qThreadInfo(options, cmd, args): + if cmd == 'qfThreadInfo': + query_type = 'first' + else: + query_type = 'subsequent' + print 'get_current_thread_list(type=%s)' % (query_type) + return False + + +def rsp_qThreadInfo(options, cmd, cmd_args, rsp): + packet = Packet(rsp) + response_type = packet.get_char() + if response_type == 'm': + tids = packet.split_hex(';', 'big') + for i, tid in enumerate(tids): + if i: + print ',', + print '0x%x' % (tid), + print + elif response_type == 'l': + print 'END' + + +def rsp_hex_big_endian(options, cmd, cmd_args, rsp): + if rsp == '': + print "%s%s is not supported" % (cmd, cmd_args) + else: + packet = Packet(rsp) + uval = packet.get_hex_uint('big') + print '%s: 0x%x' % (cmd, uval) + + +def cmd_read_mem_bin(options, cmd, args): + # x0x7fff5fc39200,0x200 + packet = Packet(args) + addr = packet.get_hex_uint('big') + comma = packet.get_char() + size = packet.get_hex_uint('big') + print 'binary_read_memory (addr = 0x%16.16x, size = %u)' % (addr, size) + return False + + +def rsp_mem_bin_bytes(options, cmd, cmd_args, rsp): + packet = Packet(cmd_args) + addr = packet.get_hex_uint('big') + comma = packet.get_char() + size = packet.get_hex_uint('big') + print 'memory:' + if size > 0: + dump_hex_memory_buffer(addr, rsp) + + +def cmd_read_memory(options, cmd, args): + packet = Packet(args) + addr = packet.get_hex_uint('big') + comma = packet.get_char() + size = packet.get_hex_uint('big') + print 'read_memory (addr = 0x%16.16x, size = %u)' % (addr, size) + return False + + +def dump_hex_memory_buffer(addr, hex_byte_str): + packet = Packet(hex_byte_str) + idx = 0 + ascii = '' + uval = packet.get_hex_uint8() + while uval is not None: + if ((idx % 16) == 0): + if ascii: + print ' ', ascii + ascii = '' + print '0x%x:' % (addr + idx), + print '%2.2x' % (uval), + if 0x20 <= uval and uval < 0x7f: + ascii += '%c' % uval + else: + ascii += '.' + uval = packet.get_hex_uint8() + idx = idx + 1 + if ascii: + print ' ', ascii + ascii = '' + + +def cmd_write_memory(options, cmd, args): + packet = Packet(args) + addr = packet.get_hex_uint('big') + if packet.get_char() != ',': + print 'error: invalid write memory command (missing comma after address)' + return + size = packet.get_hex_uint('big') + if packet.get_char() != ':': + print 'error: invalid write memory command (missing colon after size)' + return + print 'write_memory (addr = 0x%16.16x, size = %u, data:' % (addr, size) + dump_hex_memory_buffer(addr, packet.str) + return False + + +def cmd_alloc_memory(options, cmd, args): + packet = Packet(args) + byte_size = packet.get_hex_uint('big') + if packet.get_char() != ',': + print 'error: invalid allocate memory command (missing comma after address)' + return + print 'allocate_memory (byte-size = %u (0x%x), permissions = %s)' % (byte_size, byte_size, packet.str) + return False + + +def rsp_alloc_memory(options, cmd, cmd_args, rsp): + packet = Packet(rsp) + addr = packet.get_hex_uint('big') + print 'addr = 0x%x' % addr + + +def cmd_dealloc_memory(options, cmd, args): + packet = Packet(args) + addr = packet.get_hex_uint('big') + if packet.get_char() != ',': + print 'error: invalid allocate memory command (missing comma after address)' + else: + print 'deallocate_memory (addr = 0x%x, permissions = %s)' % (addr, packet.str) + return False + + +def rsp_memory_bytes(options, cmd, cmd_args, rsp): + addr = Packet(cmd_args).get_hex_uint('big') + dump_hex_memory_buffer(addr, rsp) + + +def get_register_name_equal_value(options, reg_num, hex_value_str): + if reg_num < len(g_register_infos): + reg_info = g_register_infos[reg_num] + value_str = reg_info.get_value_from_hex_string(hex_value_str) + s = reg_info.name() + ' = ' + if options.symbolicator: + symbolicated_addresses = options.symbolicator.symbolicate( + int(value_str, 0)) + if symbolicated_addresses: + s += options.colors.magenta() + s += '%s' % symbolicated_addresses[0] + s += options.colors.reset() + return s + s += value_str + return s + else: + reg_value = Packet(hex_value_str).get_hex_uint(g_byte_order) + return 'reg(%u) = 0x%x' % (reg_num, reg_value) + + +def cmd_read_one_reg(options, cmd, args): + packet = Packet(args) + reg_num = packet.get_hex_uint('big') + tid = get_thread_from_thread_suffix(packet.str) + name = None + if reg_num < len(g_register_infos): + name = g_register_infos[reg_num].name() + if packet.str: + packet.get_char() # skip ; + thread_info = packet.get_key_value_pairs() + tid = int(thread_info[0][1], 16) + s = 'read_register (reg_num=%u' % reg_num + if name: + s += ' (%s)' % (name) + if tid is not None: + s += ', tid = 0x%4.4x' % (tid) + s += ')' + print s + return False + + +def rsp_read_one_reg(options, cmd, cmd_args, rsp): + packet = Packet(cmd_args) + reg_num = packet.get_hex_uint('big') + print get_register_name_equal_value(options, reg_num, rsp) + + +def cmd_write_one_reg(options, cmd, args): + packet = Packet(args) + reg_num = packet.get_hex_uint('big') + if packet.get_char() != '=': + print 'error: invalid register write packet' + else: + name = None + hex_value_str = packet.get_hex_chars() + tid = get_thread_from_thread_suffix(packet.str) + s = 'write_register (reg_num=%u' % reg_num + if name: + s += ' (%s)' % (name) + s += ', value = ' + s += get_register_name_equal_value(options, reg_num, hex_value_str) + if tid is not None: + s += ', tid = 0x%4.4x' % (tid) + s += ')' + print s + return False + + +def dump_all_regs(packet): + for reg_info in g_register_infos: + nibble_size = reg_info.bit_size() / 4 + hex_value_str = packet.get_hex_chars(nibble_size) + if hex_value_str is not None: + value = reg_info.get_value_from_hex_string(hex_value_str) + print '%*s = %s' % (g_max_register_info_name_len, reg_info.name(), value) + else: + return + + +def cmd_read_all_regs(cmd, cmd_args): + packet = Packet(cmd_args) + packet.get_char() # toss the 'g' command character + tid = get_thread_from_thread_suffix(packet.str) + if tid is not None: + print 'read_all_register(thread = 0x%4.4x)' % tid + else: + print 'read_all_register()' + return False + + +def rsp_read_all_regs(options, cmd, cmd_args, rsp): + packet = Packet(rsp) + dump_all_regs(packet) + + +def cmd_write_all_regs(options, cmd, args): + packet = Packet(args) + print 'write_all_registers()' + dump_all_regs(packet) + return False + +g_bp_types = ["software_bp", "hardware_bp", "write_wp", "read_wp", "access_wp"] + + +def cmd_bp(options, cmd, args): + if cmd == 'Z': + s = 'set_' + else: + s = 'clear_' + packet = Packet(args) + bp_type = packet.get_hex_uint('big') + packet.get_char() # Skip , + bp_addr = packet.get_hex_uint('big') + packet.get_char() # Skip , + bp_size = packet.get_hex_uint('big') + s += g_bp_types[bp_type] + s += " (addr = 0x%x, size = %u)" % (bp_addr, bp_size) + print s + return False + + +def cmd_mem_rgn_info(options, cmd, args): + packet = Packet(args) + packet.get_char() # skip ':' character + addr = packet.get_hex_uint('big') + print 'get_memory_region_info (addr=0x%x)' % (addr) + return False + + +def cmd_kill(options, cmd, args): + print 'kill_process()' + return False + + +def cmd_jThreadsInfo(options, cmd, args): + print 'jThreadsInfo()' + return False + + +def cmd_jGetLoadedDynamicLibrariesInfos(options, cmd, args): + print 'jGetLoadedDynamicLibrariesInfos()' + return False + + +def decode_packet(s, start_index=0): + # print '\ndecode_packet("%s")' % (s[start_index:]) + index = s.find('}', start_index) + have_escapes = index != -1 + if have_escapes: + normal_s = s[start_index:index] + else: + normal_s = s[start_index:] + # print 'normal_s = "%s"' % (normal_s) + if have_escapes: + escape_char = '%c' % (ord(s[index + 1]) ^ 0x20) + # print 'escape_char for "%s" = %c' % (s[index:index+2], escape_char) + return normal_s + escape_char + decode_packet(s, index + 2) + else: + return normal_s + + +def rsp_json(options, cmd, cmd_args, rsp): + print '%s() reply:' % (cmd) + json_tree = json.loads(rsp) + print json.dumps(json_tree, indent=4, separators=(',', ': ')) + + +def rsp_jGetLoadedDynamicLibrariesInfos(options, cmd, cmd_args, rsp): + if cmd_args: + rsp_json(options, cmd, cmd_args, rsp) + else: + rsp_ok_means_supported(options, cmd, cmd_args, rsp) + +gdb_remote_commands = { + '\\?': {'cmd': cmd_stop_reply, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"}, + 'qThreadStopInfo': {'cmd': cmd_qThreadStopInfo, 'rsp': rsp_stop_reply, 'name': "stop reply pacpket"}, + 'QStartNoAckMode': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if no ack mode is supported"}, + 'QThreadSuffixSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if thread suffix is supported"}, + 'QListThreadsInStopReply': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query if threads in stop reply packets are supported"}, + 'QSetDetachOnError:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should detach on error"}, + 'QSetDisableASLR:': {'cmd': cmd_QSetWithUnsigned, 'rsp': rsp_ok_means_success, 'name': "set if we should disable ASLR"}, + 'qLaunchSuccess': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_success, 'name': "check on launch success for the A packet"}, + 'A': {'cmd': cmd_A, 'rsp': rsp_ok_means_success, 'name': "launch process"}, + 'QLaunchArch:': {'cmd': cmd_QSetWithString, 'rsp': rsp_ok_means_supported, 'name': "set the arch to launch in case the file contains multiple architectures"}, + 'qVAttachOrWaitSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "set the launch architecture"}, + 'qHostInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get host information"}, + 'qC': {'cmd': cmd_qC, 'rsp': rsp_qC, 'name': "return the current thread ID"}, + 'vCont': {'cmd': cmd_vCont, 'rsp': rsp_vCont, 'name': "extended continue command"}, + 'vAttach': {'cmd': cmd_vAttach, 'rsp': rsp_stop_reply, 'name': "attach to process"}, + 'c': {'cmd': cmd_c, 'rsp': rsp_stop_reply, 'name': "continue"}, + 's': {'cmd': cmd_s, 'rsp': rsp_stop_reply, 'name': "step"}, + 'qRegisterInfo': {'cmd': cmd_qRegisterInfo, 'rsp': rsp_qRegisterInfo, 'name': "query register info"}, + 'qfThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"}, + 'qsThreadInfo': {'cmd': cmd_qThreadInfo, 'rsp': rsp_qThreadInfo, 'name': "get current thread list"}, + 'qShlibInfoAddr': {'cmd': cmd_query_packet, 'rsp': rsp_hex_big_endian, 'name': "get shared library info address"}, + 'qMemoryRegionInfo': {'cmd': cmd_mem_rgn_info, 'rsp': rsp_dump_key_value_pairs, 'name': "get memory region information"}, + 'qProcessInfo': {'cmd': cmd_query_packet, 'rsp': rsp_dump_key_value_pairs, 'name': "get process info"}, + 'qSupported': {'cmd': cmd_query_packet, 'rsp': rsp_ok_means_supported, 'name': "query supported"}, + 'qXfer:': {'cmd': cmd_qXfer, 'rsp': rsp_qXfer, 'name': "qXfer"}, + 'qSymbol:': {'cmd': cmd_qSymbol, 'rsp': rsp_qSymbol, 'name': "qSymbol"}, + 'QSetSTDIN:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDIN prior to launching with A packet"}, + 'QSetSTDOUT:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDOUT prior to launching with A packet"}, + 'QSetSTDERR:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set STDERR prior to launching with A packet"}, + 'QEnvironment:' : {'cmd' : cmd_QSetWithString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"}, + 'QEnvironmentHexEncoded:' : {'cmd' : cmd_QSetWithHexString, 'rsp' : rsp_ok_means_success, 'name': "set an environment variable prior to launching with A packet"}, + 'x': {'cmd': cmd_read_mem_bin, 'rsp': rsp_mem_bin_bytes, 'name': "read memory binary"}, + 'X': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory binary"}, + 'm': {'cmd': cmd_read_memory, 'rsp': rsp_memory_bytes, 'name': "read memory"}, + 'M': {'cmd': cmd_write_memory, 'rsp': rsp_ok_means_success, 'name': "write memory"}, + '_M': {'cmd': cmd_alloc_memory, 'rsp': rsp_alloc_memory, 'name': "allocate memory"}, + '_m': {'cmd': cmd_dealloc_memory, 'rsp': rsp_ok_means_success, 'name': "deallocate memory"}, + 'p': {'cmd': cmd_read_one_reg, 'rsp': rsp_read_one_reg, 'name': "read single register"}, + 'P': {'cmd': cmd_write_one_reg, 'rsp': rsp_ok_means_success, 'name': "write single register"}, + 'g': {'cmd': cmd_read_all_regs, 'rsp': rsp_read_all_regs, 'name': "read all registers"}, + 'G': {'cmd': cmd_write_all_regs, 'rsp': rsp_ok_means_success, 'name': "write all registers"}, + 'z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "clear breakpoint or watchpoint"}, + 'Z': {'cmd': cmd_bp, 'rsp': rsp_ok_means_success, 'name': "set breakpoint or watchpoint"}, + 'k': {'cmd': cmd_kill, 'rsp': rsp_stop_reply, 'name': "kill process"}, + 'jThreadsInfo': {'cmd': cmd_jThreadsInfo, 'rsp': rsp_json, 'name': "JSON get all threads info"}, + 'jGetLoadedDynamicLibrariesInfos:': {'cmd': cmd_jGetLoadedDynamicLibrariesInfos, 'rsp': rsp_jGetLoadedDynamicLibrariesInfos, 'name': 'JSON get loaded dynamic libraries'}, +} + + +def calculate_mean_and_standard_deviation(floats): + sum = 0.0 + count = len(floats) + if count == 0: + return (0.0, 0.0) + for f in floats: + sum += f + mean = sum / count + accum = 0.0 + for f in floats: + delta = f - mean + accum += delta * delta + + std_dev = math.sqrt(accum / (count - 1)) + return (mean, std_dev) + + +def parse_gdb_log_file(path, options): + f = open(path) + parse_gdb_log(f, options) + f.close() + + +def parse_gdb_log(file, options): + '''Parse a GDB log file that was generated by enabling logging with: + (lldb) log enable --threadsafe --timestamp --file gdb-remote packets + This log file will contain timestamps and this function will then normalize + those packets to be relative to the first value timestamp that is found and + show delta times between log lines and also keep track of how long it takes + for GDB remote commands to make a send/receive round trip. This can be + handy when trying to figure out why some operation in the debugger is taking + a long time during a preset set of debugger commands.''' + + tricky_commands = ['qRegisterInfo'] + timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$') + packet_name_regex = re.compile('([A-Za-z_]+)[^a-z]') + packet_transmit_name_regex = re.compile( + '(?Psend|read) packet: (?P.*)') + packet_contents_name_regex = re.compile('\$([^#]*)#[0-9a-fA-F]{2}') + packet_checksum_regex = re.compile('.*#[0-9a-fA-F]{2}$') + packet_names_regex_str = '(' + \ + '|'.join(gdb_remote_commands.keys()) + ')(.*)' + packet_names_regex = re.compile(packet_names_regex_str) + + base_time = 0.0 + last_time = 0.0 + packet_send_time = 0.0 + packet_total_times = {} + packet_times = [] + packet_count = {} + lines = file.read().splitlines() + last_command = None + last_command_args = None + last_command_packet = None + hide_next_response = False + num_lines = len(lines) + skip_count = 0 + for (line_index, line) in enumerate(lines): + # See if we need to skip any lines + if skip_count > 0: + skip_count -= 1 + continue + m = packet_transmit_name_regex.search(line) + is_command = False + direction = None + if m: + direction = m.group('direction') + is_command = direction == 'send' + packet = m.group('packet') + sys.stdout.write(options.colors.green()) + if not options.quiet and not hide_next_response: + print '# ', line + sys.stdout.write(options.colors.reset()) + + # print 'direction = "%s", packet = "%s"' % (direction, packet) + + if packet[0] == '+': + if is_command: + print '-->', + else: + print '<--', + if not options.quiet: + print 'ACK' + continue + elif packet[0] == '-': + if is_command: + print '-->', + else: + print '<--', + if not options.quiet: + print 'NACK' + continue + elif packet[0] == '$': + m = packet_contents_name_regex.match(packet) + if not m and packet[0] == '$': + multiline_packet = packet + idx = line_index + 1 + while idx < num_lines: + if not options.quiet and not hide_next_response: + print '# ', lines[idx] + multiline_packet += lines[idx] + m = packet_contents_name_regex.match(multiline_packet) + if m: + packet = multiline_packet + skip_count = idx - line_index + break + else: + idx += 1 + if m: + if is_command: + print '-->', + else: + print '<--', + contents = decode_packet(m.group(1)) + if is_command: + hide_next_response = False + m = packet_names_regex.match(contents) + if m: + last_command = m.group(1) + if last_command == '?': + last_command = '\\?' + packet_name = last_command + last_command_args = m.group(2) + last_command_packet = contents + hide_next_response = gdb_remote_commands[last_command][ + 'cmd'](options, last_command, last_command_args) + else: + packet_match = packet_name_regex.match(contents) + if packet_match: + packet_name = packet_match.group(1) + for tricky_cmd in tricky_commands: + if packet_name.find(tricky_cmd) == 0: + packet_name = tricky_cmd + else: + packet_name = contents + last_command = None + last_command_args = None + last_command_packet = None + elif last_command: + gdb_remote_commands[last_command]['rsp']( + options, last_command, last_command_args, contents) + else: + print 'error: invalid packet: "', packet, '"' + else: + print '???' + else: + print '## ', line + match = timestamp_regex.match(line) + if match: + curr_time = float(match.group(2)) + if last_time and not is_command: + delta = curr_time - last_time + packet_times.append(delta) + delta = 0.0 + if base_time: + delta = curr_time - last_time + else: + base_time = curr_time + + if is_command: + packet_send_time = curr_time + elif line.find('read packet: $') >= 0 and packet_name: + if packet_name in packet_total_times: + packet_total_times[packet_name] += delta + packet_count[packet_name] += 1 + else: + packet_total_times[packet_name] = delta + packet_count[packet_name] = 1 + packet_name = None + + if not options or not options.quiet: + print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3)) + last_time = curr_time + # else: + # print line + (average, std_dev) = calculate_mean_and_standard_deviation(packet_times) + if average and std_dev: + print '%u packets with average packet time of %f and standard deviation of %f' % (len(packet_times), average, std_dev) + if packet_total_times: + total_packet_time = 0.0 + total_packet_count = 0 + for key, vvv in packet_total_times.items(): + # print ' key = (%s) "%s"' % (type(key), key) + # print 'value = (%s) %s' % (type(vvv), vvv) + # if type(vvv) == 'float': + total_packet_time += vvv + for key, vvv in packet_count.items(): + total_packet_count += vvv + + print '#---------------------------------------------------' + print '# Packet timing summary:' + print '# Totals: time = %6f, count = %6d' % (total_packet_time, total_packet_count) + print '#---------------------------------------------------' + print '# Packet Time (sec) Percent Count ' + print '#------------------------- ---------- ------- ------' + if options and options.sort_count: + res = sorted( + packet_count, + key=packet_count.__getitem__, + reverse=True) + else: + res = sorted( + packet_total_times, + key=packet_total_times.__getitem__, + reverse=True) + + if last_time > 0.0: + for item in res: + packet_total_time = packet_total_times[item] + packet_percent = ( + packet_total_time / total_packet_time) * 100.0 + if packet_percent >= 10.0: + print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item]) + else: + print " %24s %.6f %.2f%% %6d" % (item, packet_total_time, packet_percent, packet_count[item]) + + +if __name__ == '__main__': + usage = "usage: gdbremote [options]" + description = '''The command disassembles a GDB remote packet log.''' + parser = optparse.OptionParser( + description=description, + prog='gdbremote', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + parser.add_option( + '-q', + '--quiet', + action='store_true', + dest='quiet', + help='display verbose debug info', + default=False) + parser.add_option( + '-C', + '--color', + action='store_true', + dest='color', + help='add terminal colors', + default=False) + parser.add_option( + '-c', + '--sort-by-count', + action='store_true', + dest='sort_count', + help='display verbose debug info', + default=False) + parser.add_option( + '--crashlog', + type='string', + dest='crashlog', + help='symbolicate using a darwin crash log file', + default=False) + try: + (options, args) = parser.parse_args(sys.argv[1:]) + except: + print 'error: argument error' + sys.exit(1) + + options.colors = TerminalColors(options.color) + options.symbolicator = None + if options.crashlog: + import lldb + lldb.debugger = lldb.SBDebugger.Create() + import lldb.macosx.crashlog + options.symbolicator = lldb.macosx.crashlog.CrashLog(options.crashlog) + print '%s' % (options.symbolicator) + + # This script is being run from the command line, create a debugger in case we are + # going to use any debugger functions in our function. + if len(args): + for file in args: + print '#----------------------------------------------------------------------' + print "# GDB remote log file: '%s'" % file + print '#----------------------------------------------------------------------' + parse_gdb_log_file(file, options) + if options.symbolicator: + print '%s' % (options.symbolicator) + else: + parse_gdb_log(sys.stdin, options) + +else: + import lldb + if lldb.debugger: + # This initializer is being run from LLDB in the embedded command interpreter + # Add any commands contained in this module to LLDB + lldb.debugger.HandleCommand( + 'command script add -f gdbremote.start_gdb_log start_gdb_log') + lldb.debugger.HandleCommand( + 'command script add -f gdbremote.stop_gdb_log stop_gdb_log') + print 'The "start_gdb_log" and "stop_gdb_log" commands are now installed and ready for use, type "start_gdb_log --help" or "stop_gdb_log --help" for more information' diff --git a/examples/python/globals.py b/examples/python/globals.py new file mode 100755 index 000000000..43bd915b3 --- /dev/null +++ b/examples/python/globals.py @@ -0,0 +1,106 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# For the shells csh, tcsh: +# ( setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python ; ./globals.py [ ...]) +# +# For the shells sh, bash: +# PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python ./globals.py [ ...] +#---------------------------------------------------------------------- + +import lldb +import commands +import optparse +import os +import shlex +import sys + + +def get_globals(raw_path, options): + error = lldb.SBError() + # Resolve the path if needed + path = os.path.expanduser(raw_path) + # Create a target using path + options + target = lldb.debugger.CreateTarget( + path, options.arch, options.platform, False, error) + if target: + # Get the executable module + module = target.module[target.executable.basename] + if module: + # Keep track of which variables we have already looked up + global_names = list() + # Iterate through all symbols in the symbol table and watch for any + # DATA symbols + for symbol in module.symbols: + if symbol.type == lldb.eSymbolTypeData: + # The symbol is a DATA symbol, lets try and find all global variables + # that match this name and print them + global_name = symbol.name + # Make sure we don't lookup the same variable twice + if global_name not in global_names: + global_names.append(global_name) + # Find all global variables by name + global_variable_list = module.FindGlobalVariables( + target, global_name, lldb.UINT32_MAX) + if global_variable_list: + # Print results for anything that matched + for global_variable in global_variable_list: + # returns the global variable name as a string + print 'name = %s' % global_variable.name + # Returns the variable value as a string + print 'value = %s' % global_variable.value + print 'type = %s' % global_variable.type # Returns an lldb.SBType object + # Returns an lldb.SBAddress (section offset + # address) for this global + print 'addr = %s' % global_variable.addr + # Returns the file virtual address for this + # global + print 'file_addr = 0x%x' % global_variable.addr.file_addr + # returns the global variable value as a string + print 'location = %s' % global_variable.location + # Returns the size in bytes of this global + # variable + print 'size = %s' % global_variable.size + print + + +def globals(command_args): + '''Extract all globals from any arguments which must be paths to object files.''' + usage = "usage: %prog [options] [PATH ...]" + description = '''This command will find all globals in the specified object file and return an list() of lldb.SBValue objects (which might be empty).''' + parser = optparse.OptionParser( + description=description, + prog='globals', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + parser.add_option( + '-a', + '--arch', + type='string', + metavar='arch', + dest='arch', + help='Specify an architecture (or triple) to use when extracting from a file.') + parser.add_option( + '-p', + '--platform', + type='string', + metavar='platform', + dest='platform', + help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') + try: + (options, args) = parser.parse_args(command_args) + except: + return + + for path in args: + get_globals(path, options) + +if __name__ == '__main__': + lldb.debugger = lldb.SBDebugger.Create() + globals(sys.argv[1:]) diff --git a/examples/python/jump.py b/examples/python/jump.py new file mode 100644 index 000000000..6e41b4c80 --- /dev/null +++ b/examples/python/jump.py @@ -0,0 +1,196 @@ +import lldb +import re + + +def parse_linespec(linespec, frame, result): + """Handles a subset of GDB-style linespecs. Specifically: + + number - A line in the current file + +offset - The line /offset/ lines after this line + -offset - The line /offset/ lines before this line + filename:number - Line /number/ in file /filename/ + function - The start of /function/ + *address - The pointer target of /address/, which must be a literal (but see `` in LLDB) + + We explicitly do not handle filename:function because it is ambiguous in Objective-C. + + This function returns a list of addresses.""" + + breakpoint = None + target = frame.GetThread().GetProcess().GetTarget() + + matched = False + + if (not matched): + mo = re.match("^([0-9]+)$", linespec) + if (mo is not None): + matched = True + # print "Matched " + line_number = int(mo.group(1)) + line_entry = frame.GetLineEntry() + if not line_entry.IsValid(): + result.AppendMessage( + "Specified a line in the current file, but the current frame doesn't have line table information.") + return + breakpoint = target.BreakpointCreateByLocation( + line_entry.GetFileSpec(), line_number) + + if (not matched): + mo = re.match("^\+([0-9]+)$", linespec) + if (mo is not None): + matched = True + # print "Matched +" + line_number = int(mo.group(1)) + line_entry = frame.GetLineEntry() + if not line_entry.IsValid(): + result.AppendMessage( + "Specified a line in the current file, but the current frame doesn't have line table information.") + return + breakpoint = target.BreakpointCreateByLocation( + line_entry.GetFileSpec(), (line_entry.GetLine() + line_number)) + + if (not matched): + mo = re.match("^\-([0-9]+)$", linespec) + if (mo is not None): + matched = True + # print "Matched -" + line_number = int(mo.group(1)) + line_entry = frame.GetLineEntry() + if not line_entry.IsValid(): + result.AppendMessage( + "Specified a line in the current file, but the current frame doesn't have line table information.") + return + breakpoint = target.BreakpointCreateByLocation( + line_entry.GetFileSpec(), (line_entry.GetLine() - line_number)) + + if (not matched): + mo = re.match("^(.*):([0-9]+)$", linespec) + if (mo is not None): + matched = True + # print "Matched :" + file_name = mo.group(1) + line_number = int(mo.group(2)) + breakpoint = target.BreakpointCreateByLocation( + file_name, line_number) + + if (not matched): + mo = re.match("\*((0x)?([0-9a-f]+))$", linespec) + if (mo is not None): + matched = True + # print "Matched " + address = long(mo.group(1), base=0) + breakpoint = target.BreakpointCreateByAddress(address) + + if (not matched): + # print "Trying " + breakpoint = target.BreakpointCreateByName(linespec) + + num_locations = breakpoint.GetNumLocations() + + if (num_locations == 0): + result.AppendMessage( + "The line specification provided doesn't resolve to any addresses.") + + addr_list = [] + + for location_index in range(num_locations): + location = breakpoint.GetLocationAtIndex(location_index) + addr_list.append(location.GetAddress()) + + target.BreakpointDelete(breakpoint.GetID()) + + return addr_list + + +def usage_string(): + return """ Sets the program counter to a specific address. + +Syntax: jump [] + +Command Options Usage: + jump + jump + + jump - + jump : + jump + jump * + + serves to disambiguate when multiple locations could be meant.""" + + +def jump(debugger, command, result, internal_dict): + if (command == ""): + result.AppendMessage(usage_string()) + + args = command.split() + + if not debugger.IsValid(): + result.AppendMessage("Invalid debugger!") + return + + target = debugger.GetSelectedTarget() + if not target.IsValid(): + result.AppendMessage("jump requires a valid target.") + return + + process = target.GetProcess() + if not process.IsValid(): + result.AppendMessage("jump requires a valid process.") + return + + thread = process.GetSelectedThread() + if not thread.IsValid(): + result.AppendMessage("jump requires a valid thread.") + return + + frame = thread.GetSelectedFrame() + if not frame.IsValid(): + result.AppendMessage("jump requires a valid frame.") + return + + addresses = parse_linespec(args[0], frame, result) + + stream = lldb.SBStream() + + if len(addresses) == 0: + return + + desired_address = addresses[0] + + if len(addresses) > 1: + if len(args) == 2: + desired_index = int(args[1]) + if (desired_index >= 0) and (desired_index < len(addresses)): + desired_address = addresses[desired_index] + else: + result.AppendMessage( + "Desired index " + + args[1] + + " is not one of the options.") + return + else: + index = 0 + result.AppendMessage( + "The specified location resolves to multiple targets.") + for address in addresses: + stream.Clear() + address.GetDescription(stream) + result.AppendMessage( + " Location ID " + + str(index) + + ": " + + stream.GetData()) + index = index + 1 + result.AppendMessage( + "Please type 'jump " + + command + + " ' to choose one.") + return + + frame.SetPC(desired_address.GetLoadAddress(target)) + +if lldb.debugger: + # Module is being run inside the LLDB interpreter + jump.__doc__ = usage_string() + lldb.debugger.HandleCommand('command script add -f jump.jump jump') + print 'The "jump" command has been installed, type "help jump" or "jump " for detailed help.' diff --git a/examples/python/lldb_module_utils.py b/examples/python/lldb_module_utils.py new file mode 100644 index 000000000..eb00a489c --- /dev/null +++ b/examples/python/lldb_module_utils.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +import lldb +import optparse +import shlex +import string +import sys + + +def create_dump_module_line_tables_options(): + usage = "usage: dump_module_line_tables [options] MODULE1 [MODULE2 ...]" + description = '''Dumps all line tables from all compile units for any modules specified as arguments. Specifying the --verbose flag will output address ranges for each line entry.''' + parser = optparse.OptionParser( + description=description, + prog='start_gdb_log', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='Display verbose output.', + default=False) + return parser + + +def dump_module_line_tables(debugger, command, result, dict): + '''Dumps all line tables from all compile units for any modules specified as arguments.''' + command_args = shlex.split(command) + + parser = create_dump_module_line_tables_options() + try: + (options, args) = parser.parse_args(command_args) + except: + return + if command_args: + target = debugger.GetSelectedTarget() + lldb.target = target + for module_name in command_args: + result.PutCString('Searching for module "%s"' % (module_name,)) + module_fspec = lldb.SBFileSpec(module_name, False) + module = target.FindModule(module_fspec) + if module: + for cu_idx in range(module.GetNumCompileUnits()): + cu = module.GetCompileUnitAtIndex(cu_idx) + result.PutCString("\n%s:" % (cu.file)) + for line_idx in range(cu.GetNumLineEntries()): + line_entry = cu.GetLineEntryAtIndex(line_idx) + start_file_addr = line_entry.addr.file_addr + end_file_addr = line_entry.end_addr.file_addr + # If the two addresses are equal, this line table entry + # is a termination entry + if options.verbose: + if start_file_addr != end_file_addr: + result.PutCString( + '[%#x - %#x): %s' % + (start_file_addr, end_file_addr, line_entry)) + else: + if start_file_addr == end_file_addr: + result.PutCString('%#x: END' % + (start_file_addr)) + else: + result.PutCString( + '%#x: %s' % + (start_file_addr, line_entry)) + if start_file_addr == end_file_addr: + result.Printf("\n") + else: + result.PutCString("no module for '%s'" % module) + else: + result.PutCString("error: invalid target") + +parser = create_dump_module_line_tables_options() +dump_module_line_tables.__doc__ = parser.format_help() +lldb.debugger.HandleCommand( + 'command script add -f %s.dump_module_line_tables dump_module_line_tables' % + __name__) +print 'Installed "dump_module_line_tables" command' diff --git a/examples/python/lldbtk.py b/examples/python/lldbtk.py new file mode 100644 index 000000000..a978b9e07 --- /dev/null +++ b/examples/python/lldbtk.py @@ -0,0 +1,613 @@ +#!/usr/bin/python + +import lldb +import shlex +import sys +from Tkinter import * +import ttk + + +class ValueTreeItemDelegate(object): + + def __init__(self, value): + self.value = value + + def get_item_dictionary(self): + name = self.value.name + if name is None: + name = '' + typename = self.value.type + if typename is None: + typename = '' + value = self.value.value + if value is None: + value = '' + summary = self.value.summary + if summary is None: + summary = '' + has_children = self.value.MightHaveChildren() + return {'#0': name, + 'typename': typename, + 'value': value, + 'summary': summary, + 'children': has_children, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + for i in range(self.value.num_children): + item_delegate = ValueTreeItemDelegate( + self.value.GetChildAtIndex(i)) + item_dicts.append(item_delegate.get_item_dictionary()) + return item_dicts + + +class FrameTreeItemDelegate(object): + + def __init__(self, frame): + self.frame = frame + + def get_item_dictionary(self): + id = self.frame.GetFrameID() + name = 'frame #%u' % (id) + value = '0x%16.16x' % (self.frame.GetPC()) + stream = lldb.SBStream() + self.frame.GetDescription(stream) + summary = stream.GetData().split("`")[1] + return { + '#0': name, + 'value': value, + 'summary': summary, + 'children': self.frame.GetVariables( + True, + True, + True, + True).GetSize() > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + variables = self.frame.GetVariables(True, True, True, True) + n = variables.GetSize() + for i in range(n): + item_delegate = ValueTreeItemDelegate(variables[i]) + item_dicts.append(item_delegate.get_item_dictionary()) + return item_dicts + + +class ThreadTreeItemDelegate(object): + + def __init__(self, thread): + self.thread = thread + + def get_item_dictionary(self): + num_frames = self.thread.GetNumFrames() + name = 'thread #%u' % (self.thread.GetIndexID()) + value = '0x%x' % (self.thread.GetThreadID()) + summary = '%u frames' % (num_frames) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': num_frames > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + for frame in self.thread: + item_delegate = FrameTreeItemDelegate(frame) + item_dicts.append(item_delegate.get_item_dictionary()) + return item_dicts + + +class ProcessTreeItemDelegate(object): + + def __init__(self, process): + self.process = process + + def get_item_dictionary(self): + id = self.process.GetProcessID() + num_threads = self.process.GetNumThreads() + value = str(self.process.GetProcessID()) + summary = self.process.target.executable.fullpath + return {'#0': 'process', + 'value': value, + 'summary': summary, + 'children': num_threads > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + for thread in self.process: + item_delegate = ThreadTreeItemDelegate(thread) + item_dicts.append(item_delegate.get_item_dictionary()) + return item_dicts + + +class TargetTreeItemDelegate(object): + + def __init__(self, target): + self.target = target + + def get_item_dictionary(self): + value = str(self.target.triple) + summary = self.target.executable.fullpath + return {'#0': 'target', + 'value': value, + 'summary': summary, + 'children': True, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + image_item_delegate = TargetImagesTreeItemDelegate(self.target) + item_dicts.append(image_item_delegate.get_item_dictionary()) + return item_dicts + + +class TargetImagesTreeItemDelegate(object): + + def __init__(self, target): + self.target = target + + def get_item_dictionary(self): + value = str(self.target.triple) + summary = self.target.executable.fullpath + num_modules = self.target.GetNumModules() + return {'#0': 'images', + 'value': '', + 'summary': '%u images' % num_modules, + 'children': num_modules > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + for i in range(self.target.GetNumModules()): + module = self.target.GetModuleAtIndex(i) + image_item_delegate = ModuleTreeItemDelegate( + self.target, module, i) + item_dicts.append(image_item_delegate.get_item_dictionary()) + return item_dicts + + +class ModuleTreeItemDelegate(object): + + def __init__(self, target, module, index): + self.target = target + self.module = module + self.index = index + + def get_item_dictionary(self): + name = 'module %u' % (self.index) + value = self.module.file.basename + summary = self.module.file.dirname + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': True, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + sections_item_delegate = ModuleSectionsTreeItemDelegate( + self.target, self.module) + item_dicts.append(sections_item_delegate.get_item_dictionary()) + + symbols_item_delegate = ModuleSymbolsTreeItemDelegate( + self.target, self.module) + item_dicts.append(symbols_item_delegate.get_item_dictionary()) + + comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate( + self.target, self.module) + item_dicts.append(comp_units_item_delegate.get_item_dictionary()) + return item_dicts + + +class ModuleSectionsTreeItemDelegate(object): + + def __init__(self, target, module): + self.target = target + self.module = module + + def get_item_dictionary(self): + name = 'sections' + value = '' + summary = '%u sections' % (self.module.GetNumSections()) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': True, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + num_sections = self.module.GetNumSections() + for i in range(num_sections): + section = self.module.GetSectionAtIndex(i) + image_item_delegate = SectionTreeItemDelegate(self.target, section) + item_dicts.append(image_item_delegate.get_item_dictionary()) + return item_dicts + + +class SectionTreeItemDelegate(object): + + def __init__(self, target, section): + self.target = target + self.section = section + + def get_item_dictionary(self): + name = self.section.name + section_load_addr = self.section.GetLoadAddress(self.target) + if section_load_addr != lldb.LLDB_INVALID_ADDRESS: + value = '0x%16.16x' % (section_load_addr) + else: + value = '0x%16.16x *' % (self.section.file_addr) + summary = '' + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': self.section.GetNumSubSections() > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + num_sections = self.section.GetNumSubSections() + for i in range(num_sections): + section = self.section.GetSubSectionAtIndex(i) + image_item_delegate = SectionTreeItemDelegate(self.target, section) + item_dicts.append(image_item_delegate.get_item_dictionary()) + return item_dicts + + +class ModuleCompileUnitsTreeItemDelegate(object): + + def __init__(self, target, module): + self.target = target + self.module = module + + def get_item_dictionary(self): + name = 'compile units' + value = '' + summary = '%u compile units' % (self.module.GetNumSections()) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': self.module.GetNumCompileUnits() > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + num_cus = self.module.GetNumCompileUnits() + for i in range(num_cus): + cu = self.module.GetCompileUnitAtIndex(i) + image_item_delegate = CompileUnitTreeItemDelegate(self.target, cu) + item_dicts.append(image_item_delegate.get_item_dictionary()) + return item_dicts + + +class CompileUnitTreeItemDelegate(object): + + def __init__(self, target, cu): + self.target = target + self.cu = cu + + def get_item_dictionary(self): + name = self.cu.GetFileSpec().basename + value = '' + num_lines = self.cu.GetNumLineEntries() + summary = '' + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': num_lines > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + item_delegate = LineTableTreeItemDelegate(self.target, self.cu) + item_dicts.append(item_delegate.get_item_dictionary()) + return item_dicts + + +class LineTableTreeItemDelegate(object): + + def __init__(self, target, cu): + self.target = target + self.cu = cu + + def get_item_dictionary(self): + name = 'line table' + value = '' + num_lines = self.cu.GetNumLineEntries() + summary = '%u line entries' % (num_lines) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': num_lines > 0, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + num_lines = self.cu.GetNumLineEntries() + for i in range(num_lines): + line_entry = self.cu.GetLineEntryAtIndex(i) + item_delegate = LineEntryTreeItemDelegate( + self.target, line_entry, i) + item_dicts.append(item_delegate.get_item_dictionary()) + return item_dicts + + +class LineEntryTreeItemDelegate(object): + + def __init__(self, target, line_entry, index): + self.target = target + self.line_entry = line_entry + self.index = index + + def get_item_dictionary(self): + name = str(self.index) + address = self.line_entry.GetStartAddress() + load_addr = address.GetLoadAddress(self.target) + if load_addr != lldb.LLDB_INVALID_ADDRESS: + value = '0x%16.16x' % (load_addr) + else: + value = '0x%16.16x *' % (address.file_addr) + summary = self.line_entry.GetFileSpec().fullpath + ':' + \ + str(self.line_entry.line) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': False, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + return item_dicts + + +class InstructionTreeItemDelegate(object): + + def __init__(self, target, instr): + self.target = target + self.instr = instr + + def get_item_dictionary(self): + address = self.instr.GetAddress() + load_addr = address.GetLoadAddress(self.target) + if load_addr != lldb.LLDB_INVALID_ADDRESS: + name = '0x%16.16x' % (load_addr) + else: + name = '0x%16.16x *' % (address.file_addr) + value = self.instr.GetMnemonic( + self.target) + ' ' + self.instr.GetOperands(self.target) + summary = self.instr.GetComment(self.target) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': False, + 'tree-item-delegate': self} + + +class ModuleSymbolsTreeItemDelegate(object): + + def __init__(self, target, module): + self.target = target + self.module = module + + def get_item_dictionary(self): + name = 'symbols' + value = '' + summary = '%u symbols' % (self.module.GetNumSymbols()) + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': True, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + num_symbols = self.module.GetNumSymbols() + for i in range(num_symbols): + symbol = self.module.GetSymbolAtIndex(i) + image_item_delegate = SymbolTreeItemDelegate( + self.target, symbol, i) + item_dicts.append(image_item_delegate.get_item_dictionary()) + return item_dicts + + +class SymbolTreeItemDelegate(object): + + def __init__(self, target, symbol, index): + self.target = target + self.symbol = symbol + self.index = index + + def get_item_dictionary(self): + address = self.symbol.GetStartAddress() + name = '[%u]' % self.index + symbol_load_addr = address.GetLoadAddress(self.target) + if symbol_load_addr != lldb.LLDB_INVALID_ADDRESS: + value = '0x%16.16x' % (symbol_load_addr) + else: + value = '0x%16.16x *' % (address.file_addr) + summary = self.symbol.name + return {'#0': name, + 'value': value, + 'summary': summary, + 'children': False, + 'tree-item-delegate': self} + + def get_child_item_dictionaries(self): + item_dicts = list() + return item_dicts + + +class DelegateTree(ttk.Frame): + + def __init__(self, column_dicts, delegate, title, name): + ttk.Frame.__init__(self, name=name) + self.pack(expand=Y, fill=BOTH) + self.master.title(title) + self.delegate = delegate + self.columns_dicts = column_dicts + self.item_id_to_item_dict = dict() + frame = Frame(self) + frame.pack(side=TOP, fill=BOTH, expand=Y) + self._create_treeview(frame) + self._populate_root() + + def _create_treeview(self, parent): + frame = ttk.Frame(parent) + frame.pack(side=TOP, fill=BOTH, expand=Y) + + column_ids = list() + for i in range(1, len(self.columns_dicts)): + column_ids.append(self.columns_dicts[i]['id']) + # create the tree and scrollbars + self.tree = ttk.Treeview(columns=column_ids) + + scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview) + scroll_bar_h = ttk.Scrollbar( + orient=HORIZONTAL, command=self.tree.xview) + self.tree['yscroll'] = scroll_bar_v.set + self.tree['xscroll'] = scroll_bar_h.set + + # setup column headings and columns properties + for columns_dict in self.columns_dicts: + self.tree.heading( + columns_dict['id'], + text=columns_dict['text'], + anchor=columns_dict['anchor']) + self.tree.column( + columns_dict['id'], + stretch=columns_dict['stretch']) + + # add tree and scrollbars to frame + self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW) + scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS) + scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW) + + # set frame resizing priorities + frame.rowconfigure(0, weight=1) + frame.columnconfigure(0, weight=1) + + # action to perform when a node is expanded + self.tree.bind('<>', self._update_tree) + + def insert_items(self, parent_id, item_dicts): + for item_dict in item_dicts: + name = None + values = list() + first = True + for columns_dict in self.columns_dicts: + if first: + name = item_dict[columns_dict['id']] + first = False + else: + values.append(item_dict[columns_dict['id']]) + item_id = self.tree.insert(parent_id, # root item has an empty name + END, + text=name, + values=values) + self.item_id_to_item_dict[item_id] = item_dict + if item_dict['children']: + self.tree.insert(item_id, END, text='dummy') + + def _populate_root(self): + # use current directory as root node + self.insert_items('', self.delegate.get_child_item_dictionaries()) + + def _update_tree(self, event): + # user expanded a node - build the related directory + item_id = self.tree.focus() # the id of the expanded node + children = self.tree.get_children(item_id) + if len(children): + first_child = children[0] + # if the node only has a 'dummy' child, remove it and + # build new directory; skip if the node is already + # populated + if self.tree.item(first_child, option='text') == 'dummy': + self.tree.delete(first_child) + item_dict = self.item_id_to_item_dict[item_id] + item_dicts = item_dict[ + 'tree-item-delegate'].get_child_item_dictionaries() + self.insert_items(item_id, item_dicts) + + +@lldb.command("tk-variables") +def tk_variable_display(debugger, command, result, dict): + # needed for tree creation in TK library as it uses sys.argv... + sys.argv = ['tk-variables'] + target = debugger.GetSelectedTarget() + if not target: + print >>result, "invalid target" + return + process = target.GetProcess() + if not process: + print >>result, "invalid process" + return + thread = process.GetSelectedThread() + if not thread: + print >>result, "invalid thread" + return + frame = thread.GetSelectedFrame() + if not frame: + print >>result, "invalid frame" + return + # Parse command line args + command_args = shlex.split(command) + column_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0}, + {'id': 'typename', 'text': 'Type', 'anchor': W, 'stretch': 0}, + {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0}, + {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}] + tree = DelegateTree( + column_dicts, + FrameTreeItemDelegate(frame), + 'Variables', + 'lldb-tk-variables') + tree.mainloop() + + +@lldb.command("tk-process") +def tk_process_display(debugger, command, result, dict): + # needed for tree creation in TK library as it uses sys.argv... + sys.argv = ['tk-process'] + target = debugger.GetSelectedTarget() + if not target: + print >>result, "invalid target" + return + process = target.GetProcess() + if not process: + print >>result, "invalid process" + return + # Parse command line args + columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0}, + {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0}, + {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}] + command_args = shlex.split(command) + tree = DelegateTree( + columnd_dicts, + ProcessTreeItemDelegate(process), + 'Process', + 'lldb-tk-process') + tree.mainloop() + + +@lldb.command("tk-target") +def tk_target_display(debugger, command, result, dict): + # needed for tree creation in TK library as it uses sys.argv... + sys.argv = ['tk-target'] + target = debugger.GetSelectedTarget() + if not target: + print >>result, "invalid target" + return + # Parse command line args + columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0}, + {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0}, + {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}] + command_args = shlex.split(command) + tree = DelegateTree( + columnd_dicts, + TargetTreeItemDelegate(target), + 'Target', + 'lldb-tk-target') + tree.mainloop() diff --git a/examples/python/mach_o.py b/examples/python/mach_o.py new file mode 100755 index 000000000..faa05ac83 --- /dev/null +++ b/examples/python/mach_o.py @@ -0,0 +1,1845 @@ +#!/usr/bin/python + +import cmd +import dict_utils +import file_extract +import optparse +import re +import struct +import string +import StringIO +import sys +import uuid + +# Mach header "magic" constants +MH_MAGIC = 0xfeedface +MH_CIGAM = 0xcefaedfe +MH_MAGIC_64 = 0xfeedfacf +MH_CIGAM_64 = 0xcffaedfe +FAT_MAGIC = 0xcafebabe +FAT_CIGAM = 0xbebafeca + +# Mach haeder "filetype" constants +MH_OBJECT = 0x00000001 +MH_EXECUTE = 0x00000002 +MH_FVMLIB = 0x00000003 +MH_CORE = 0x00000004 +MH_PRELOAD = 0x00000005 +MH_DYLIB = 0x00000006 +MH_DYLINKER = 0x00000007 +MH_BUNDLE = 0x00000008 +MH_DYLIB_STUB = 0x00000009 +MH_DSYM = 0x0000000a +MH_KEXT_BUNDLE = 0x0000000b + +# Mach haeder "flag" constant bits +MH_NOUNDEFS = 0x00000001 +MH_INCRLINK = 0x00000002 +MH_DYLDLINK = 0x00000004 +MH_BINDATLOAD = 0x00000008 +MH_PREBOUND = 0x00000010 +MH_SPLIT_SEGS = 0x00000020 +MH_LAZY_INIT = 0x00000040 +MH_TWOLEVEL = 0x00000080 +MH_FORCE_FLAT = 0x00000100 +MH_NOMULTIDEFS = 0x00000200 +MH_NOFIXPREBINDING = 0x00000400 +MH_PREBINDABLE = 0x00000800 +MH_ALLMODSBOUND = 0x00001000 +MH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000 +MH_CANONICAL = 0x00004000 +MH_WEAK_DEFINES = 0x00008000 +MH_BINDS_TO_WEAK = 0x00010000 +MH_ALLOW_STACK_EXECUTION = 0x00020000 +MH_ROOT_SAFE = 0x00040000 +MH_SETUID_SAFE = 0x00080000 +MH_NO_REEXPORTED_DYLIBS = 0x00100000 +MH_PIE = 0x00200000 +MH_DEAD_STRIPPABLE_DYLIB = 0x00400000 +MH_HAS_TLV_DESCRIPTORS = 0x00800000 +MH_NO_HEAP_EXECUTION = 0x01000000 + +# Mach load command constants +LC_REQ_DYLD = 0x80000000 +LC_SEGMENT = 0x00000001 +LC_SYMTAB = 0x00000002 +LC_SYMSEG = 0x00000003 +LC_THREAD = 0x00000004 +LC_UNIXTHREAD = 0x00000005 +LC_LOADFVMLIB = 0x00000006 +LC_IDFVMLIB = 0x00000007 +LC_IDENT = 0x00000008 +LC_FVMFILE = 0x00000009 +LC_PREPAGE = 0x0000000a +LC_DYSYMTAB = 0x0000000b +LC_LOAD_DYLIB = 0x0000000c +LC_ID_DYLIB = 0x0000000d +LC_LOAD_DYLINKER = 0x0000000e +LC_ID_DYLINKER = 0x0000000f +LC_PREBOUND_DYLIB = 0x00000010 +LC_ROUTINES = 0x00000011 +LC_SUB_FRAMEWORK = 0x00000012 +LC_SUB_UMBRELLA = 0x00000013 +LC_SUB_CLIENT = 0x00000014 +LC_SUB_LIBRARY = 0x00000015 +LC_TWOLEVEL_HINTS = 0x00000016 +LC_PREBIND_CKSUM = 0x00000017 +LC_LOAD_WEAK_DYLIB = 0x00000018 | LC_REQ_DYLD +LC_SEGMENT_64 = 0x00000019 +LC_ROUTINES_64 = 0x0000001a +LC_UUID = 0x0000001b +LC_RPATH = 0x0000001c | LC_REQ_DYLD +LC_CODE_SIGNATURE = 0x0000001d +LC_SEGMENT_SPLIT_INFO = 0x0000001e +LC_REEXPORT_DYLIB = 0x0000001f | LC_REQ_DYLD +LC_LAZY_LOAD_DYLIB = 0x00000020 +LC_ENCRYPTION_INFO = 0x00000021 +LC_DYLD_INFO = 0x00000022 +LC_DYLD_INFO_ONLY = 0x00000022 | LC_REQ_DYLD +LC_LOAD_UPWARD_DYLIB = 0x00000023 | LC_REQ_DYLD +LC_VERSION_MIN_MACOSX = 0x00000024 +LC_VERSION_MIN_IPHONEOS = 0x00000025 +LC_FUNCTION_STARTS = 0x00000026 +LC_DYLD_ENVIRONMENT = 0x00000027 + +# Mach CPU constants +CPU_ARCH_MASK = 0xff000000 +CPU_ARCH_ABI64 = 0x01000000 +CPU_TYPE_ANY = 0xffffffff +CPU_TYPE_VAX = 1 +CPU_TYPE_MC680x0 = 6 +CPU_TYPE_I386 = 7 +CPU_TYPE_X86_64 = CPU_TYPE_I386 | CPU_ARCH_ABI64 +CPU_TYPE_MIPS = 8 +CPU_TYPE_MC98000 = 10 +CPU_TYPE_HPPA = 11 +CPU_TYPE_ARM = 12 +CPU_TYPE_MC88000 = 13 +CPU_TYPE_SPARC = 14 +CPU_TYPE_I860 = 15 +CPU_TYPE_ALPHA = 16 +CPU_TYPE_POWERPC = 18 +CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64 + +# VM protection constants +VM_PROT_READ = 1 +VM_PROT_WRITE = 2 +VM_PROT_EXECUTE = 4 + +# VM protection constants +N_STAB = 0xe0 +N_PEXT = 0x10 +N_TYPE = 0x0e +N_EXT = 0x01 + +# Values for nlist N_TYPE bits of the "Mach.NList.type" field. +N_UNDF = 0x0 +N_ABS = 0x2 +N_SECT = 0xe +N_PBUD = 0xc +N_INDR = 0xa + +# Section indexes for the "Mach.NList.sect_idx" fields +NO_SECT = 0 +MAX_SECT = 255 + +# Stab defines +N_GSYM = 0x20 +N_FNAME = 0x22 +N_FUN = 0x24 +N_STSYM = 0x26 +N_LCSYM = 0x28 +N_BNSYM = 0x2e +N_OPT = 0x3c +N_RSYM = 0x40 +N_SLINE = 0x44 +N_ENSYM = 0x4e +N_SSYM = 0x60 +N_SO = 0x64 +N_OSO = 0x66 +N_LSYM = 0x80 +N_BINCL = 0x82 +N_SOL = 0x84 +N_PARAMS = 0x86 +N_VERSION = 0x88 +N_OLEVEL = 0x8A +N_PSYM = 0xa0 +N_EINCL = 0xa2 +N_ENTRY = 0xa4 +N_LBRAC = 0xc0 +N_EXCL = 0xc2 +N_RBRAC = 0xe0 +N_BCOMM = 0xe2 +N_ECOMM = 0xe4 +N_ECOML = 0xe8 +N_LENG = 0xfe + +vm_prot_names = ['---', 'r--', '-w-', 'rw-', '--x', 'r-x', '-wx', 'rwx'] + + +def dump_memory(base_addr, data, hex_bytes_len, num_per_line): + hex_bytes = data.encode('hex') + if hex_bytes_len == -1: + hex_bytes_len = len(hex_bytes) + addr = base_addr + ascii_str = '' + i = 0 + while i < hex_bytes_len: + if ((i / 2) % num_per_line) == 0: + if i > 0: + print ' %s' % (ascii_str) + ascii_str = '' + print '0x%8.8x:' % (addr + i), + hex_byte = hex_bytes[i:i + 2] + print hex_byte, + int_byte = int(hex_byte, 16) + ascii_char = '%c' % (int_byte) + if int_byte >= 32 and int_byte < 127: + ascii_str += ascii_char + else: + ascii_str += '.' + i = i + 2 + if ascii_str: + if (i / 2) % num_per_line: + padding = num_per_line - ((i / 2) % num_per_line) + else: + padding = 0 + print '%*s%s' % (padding * 3 + 1, '', ascii_str) + print + + +class TerminalColors: + '''Simple terminal colors class''' + + def __init__(self, enabled=True): + # TODO: discover terminal type from "file" and disable if + # it can't handle the color codes + self.enabled = enabled + + def reset(self): + '''Reset all terminal colors and formatting.''' + if self.enabled: + return "\x1b[0m" + return '' + + def bold(self, on=True): + '''Enable or disable bold depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[1m" + else: + return "\x1b[22m" + return '' + + def italics(self, on=True): + '''Enable or disable italics depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[3m" + else: + return "\x1b[23m" + return '' + + def underline(self, on=True): + '''Enable or disable underline depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[4m" + else: + return "\x1b[24m" + return '' + + def inverse(self, on=True): + '''Enable or disable inverse depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[7m" + else: + return "\x1b[27m" + return '' + + def strike(self, on=True): + '''Enable or disable strike through depending on the "on" parameter.''' + if self.enabled: + if on: + return "\x1b[9m" + else: + return "\x1b[29m" + return '' + + def black(self, fg=True): + '''Set the foreground or background color to black. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[30m" + else: + return "\x1b[40m" + return '' + + def red(self, fg=True): + '''Set the foreground or background color to red. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[31m" + else: + return "\x1b[41m" + return '' + + def green(self, fg=True): + '''Set the foreground or background color to green. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[32m" + else: + return "\x1b[42m" + return '' + + def yellow(self, fg=True): + '''Set the foreground or background color to yellow. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[43m" + else: + return "\x1b[33m" + return '' + + def blue(self, fg=True): + '''Set the foreground or background color to blue. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[34m" + else: + return "\x1b[44m" + return '' + + def magenta(self, fg=True): + '''Set the foreground or background color to magenta. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[35m" + else: + return "\x1b[45m" + return '' + + def cyan(self, fg=True): + '''Set the foreground or background color to cyan. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[36m" + else: + return "\x1b[46m" + return '' + + def white(self, fg=True): + '''Set the foreground or background color to white. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[37m" + else: + return "\x1b[47m" + return '' + + def default(self, fg=True): + '''Set the foreground or background color to the default. + The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' + if self.enabled: + if fg: + return "\x1b[39m" + else: + return "\x1b[49m" + return '' + + +def swap_unpack_char(): + """Returns the unpack prefix that will for non-native endian-ness.""" + if struct.pack('H', 1).startswith("\x00"): + return '<' + return '>' + + +def dump_hex_bytes(addr, s, bytes_per_line=16): + i = 0 + line = '' + for ch in s: + if (i % bytes_per_line) == 0: + if line: + print line + line = '%#8.8x: ' % (addr + i) + line += "%02X " % ord(ch) + i += 1 + print line + + +def dump_hex_byte_string_diff(addr, a, b, bytes_per_line=16): + i = 0 + line = '' + a_len = len(a) + b_len = len(b) + if a_len < b_len: + max_len = b_len + else: + max_len = a_len + tty_colors = TerminalColors(True) + for i in range(max_len): + ch = None + if i < a_len: + ch_a = a[i] + ch = ch_a + else: + ch_a = None + if i < b_len: + ch_b = b[i] + if not ch: + ch = ch_b + else: + ch_b = None + mismatch = ch_a != ch_b + if (i % bytes_per_line) == 0: + if line: + print line + line = '%#8.8x: ' % (addr + i) + if mismatch: + line += tty_colors.red() + line += "%02X " % ord(ch) + if mismatch: + line += tty_colors.default() + i += 1 + + print line + + +class Mach: + """Class that does everything mach-o related""" + + class Arch: + """Class that implements mach-o architectures""" + + def __init__(self, c=0, s=0): + self.cpu = c + self.sub = s + + def set_cpu_type(self, c): + self.cpu = c + + def set_cpu_subtype(self, s): + self.sub = s + + def set_arch(self, c, s): + self.cpu = c + self.sub = s + + def is_64_bit(self): + return (self.cpu & CPU_ARCH_ABI64) != 0 + + cpu_infos = [ + ["arm", CPU_TYPE_ARM, CPU_TYPE_ANY], + ["arm", CPU_TYPE_ARM, 0], + ["armv4", CPU_TYPE_ARM, 5], + ["armv6", CPU_TYPE_ARM, 6], + ["armv5", CPU_TYPE_ARM, 7], + ["xscale", CPU_TYPE_ARM, 8], + ["armv7", CPU_TYPE_ARM, 9], + ["armv7f", CPU_TYPE_ARM, 10], + ["armv7s", CPU_TYPE_ARM, 11], + ["armv7k", CPU_TYPE_ARM, 12], + ["armv7m", CPU_TYPE_ARM, 15], + ["armv7em", CPU_TYPE_ARM, 16], + ["ppc", CPU_TYPE_POWERPC, CPU_TYPE_ANY], + ["ppc", CPU_TYPE_POWERPC, 0], + ["ppc601", CPU_TYPE_POWERPC, 1], + ["ppc602", CPU_TYPE_POWERPC, 2], + ["ppc603", CPU_TYPE_POWERPC, 3], + ["ppc603e", CPU_TYPE_POWERPC, 4], + ["ppc603ev", CPU_TYPE_POWERPC, 5], + ["ppc604", CPU_TYPE_POWERPC, 6], + ["ppc604e", CPU_TYPE_POWERPC, 7], + ["ppc620", CPU_TYPE_POWERPC, 8], + ["ppc750", CPU_TYPE_POWERPC, 9], + ["ppc7400", CPU_TYPE_POWERPC, 10], + ["ppc7450", CPU_TYPE_POWERPC, 11], + ["ppc970", CPU_TYPE_POWERPC, 100], + ["ppc64", CPU_TYPE_POWERPC64, 0], + ["ppc970-64", CPU_TYPE_POWERPC64, 100], + ["i386", CPU_TYPE_I386, 3], + ["i486", CPU_TYPE_I386, 4], + ["i486sx", CPU_TYPE_I386, 0x84], + ["i386", CPU_TYPE_I386, CPU_TYPE_ANY], + ["x86_64", CPU_TYPE_X86_64, 3], + ["x86_64", CPU_TYPE_X86_64, CPU_TYPE_ANY], + ] + + def __str__(self): + for info in self.cpu_infos: + if self.cpu == info[1] and (self.sub & 0x00ffffff) == info[2]: + return info[0] + return "{0}.{1}".format(self.cpu, self.sub) + + class Magic(dict_utils.Enum): + + enum = { + 'MH_MAGIC': MH_MAGIC, + 'MH_CIGAM': MH_CIGAM, + 'MH_MAGIC_64': MH_MAGIC_64, + 'MH_CIGAM_64': MH_CIGAM_64, + 'FAT_MAGIC': FAT_MAGIC, + 'FAT_CIGAM': FAT_CIGAM + } + + def __init__(self, initial_value=0): + dict_utils.Enum.__init__(self, initial_value, self.enum) + + def is_skinny_mach_file(self): + return self.value == MH_MAGIC or self.value == MH_CIGAM or self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64 + + def is_universal_mach_file(self): + return self.value == FAT_MAGIC or self.value == FAT_CIGAM + + def unpack(self, data): + data.set_byte_order('native') + self.value = data.get_uint32() + + def get_byte_order(self): + if self.value == MH_CIGAM or self.value == MH_CIGAM_64 or self.value == FAT_CIGAM: + return swap_unpack_char() + else: + return '=' + + def is_64_bit(self): + return self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64 + + def __init__(self): + self.magic = Mach.Magic() + self.content = None + self.path = None + + def extract(self, path, extractor): + self.path = path + self.unpack(extractor) + + def parse(self, path): + self.path = path + try: + f = open(self.path) + file_extractor = file_extract.FileExtract(f, '=') + self.unpack(file_extractor) + # f.close() + except IOError as xxx_todo_changeme: + (errno, strerror) = xxx_todo_changeme.args + print "I/O error({0}): {1}".format(errno, strerror) + except ValueError: + print "Could not convert data to an integer." + except: + print "Unexpected error:", sys.exc_info()[0] + raise + + def compare(self, rhs): + self.content.compare(rhs.content) + + def dump(self, options=None): + self.content.dump(options) + + def dump_header(self, dump_description=True, options=None): + self.content.dump_header(dump_description, options) + + def dump_load_commands(self, dump_description=True, options=None): + self.content.dump_load_commands(dump_description, options) + + def dump_sections(self, dump_description=True, options=None): + self.content.dump_sections(dump_description, options) + + def dump_section_contents(self, options): + self.content.dump_section_contents(options) + + def dump_symtab(self, dump_description=True, options=None): + self.content.dump_symtab(dump_description, options) + + def dump_symbol_names_matching_regex(self, regex, file=None): + self.content.dump_symbol_names_matching_regex(regex, file) + + def description(self): + return self.content.description() + + def unpack(self, data): + self.magic.unpack(data) + if self.magic.is_skinny_mach_file(): + self.content = Mach.Skinny(self.path) + elif self.magic.is_universal_mach_file(): + self.content = Mach.Universal(self.path) + else: + self.content = None + + if self.content is not None: + self.content.unpack(data, self.magic) + + def is_valid(self): + return self.content is not None + + class Universal: + + def __init__(self, path): + self.path = path + self.type = 'universal' + self.file_off = 0 + self.magic = None + self.nfat_arch = 0 + self.archs = list() + + def description(self): + s = '%#8.8x: %s (' % (self.file_off, self.path) + archs_string = '' + for arch in self.archs: + if len(archs_string): + archs_string += ', ' + archs_string += '%s' % arch.arch + s += archs_string + s += ')' + return s + + def unpack(self, data, magic=None): + self.file_off = data.tell() + if magic is None: + self.magic = Mach.Magic() + self.magic.unpack(data) + else: + self.magic = magic + self.file_off = self.file_off - 4 + # Universal headers are always in big endian + data.set_byte_order('big') + self.nfat_arch = data.get_uint32() + for i in range(self.nfat_arch): + self.archs.append(Mach.Universal.ArchInfo()) + self.archs[i].unpack(data) + for i in range(self.nfat_arch): + self.archs[i].mach = Mach.Skinny(self.path) + data.seek(self.archs[i].offset, 0) + skinny_magic = Mach.Magic() + skinny_magic.unpack(data) + self.archs[i].mach.unpack(data, skinny_magic) + + def compare(self, rhs): + print 'error: comparing two universal files is not supported yet' + return False + + def dump(self, options): + if options.dump_header: + print + print "Universal Mach File: magic = %s, nfat_arch = %u" % (self.magic, self.nfat_arch) + print + if self.nfat_arch > 0: + if options.dump_header: + self.archs[0].dump_header(True, options) + for i in range(self.nfat_arch): + self.archs[i].dump_flat(options) + if options.dump_header: + print + for i in range(self.nfat_arch): + self.archs[i].mach.dump(options) + + def dump_header(self, dump_description=True, options=None): + if dump_description: + print self.description() + for i in range(self.nfat_arch): + self.archs[i].mach.dump_header(True, options) + print + + def dump_load_commands(self, dump_description=True, options=None): + if dump_description: + print self.description() + for i in range(self.nfat_arch): + self.archs[i].mach.dump_load_commands(True, options) + print + + def dump_sections(self, dump_description=True, options=None): + if dump_description: + print self.description() + for i in range(self.nfat_arch): + self.archs[i].mach.dump_sections(True, options) + print + + def dump_section_contents(self, options): + for i in range(self.nfat_arch): + self.archs[i].mach.dump_section_contents(options) + print + + def dump_symtab(self, dump_description=True, options=None): + if dump_description: + print self.description() + for i in range(self.nfat_arch): + self.archs[i].mach.dump_symtab(True, options) + print + + def dump_symbol_names_matching_regex(self, regex, file=None): + for i in range(self.nfat_arch): + self.archs[i].mach.dump_symbol_names_matching_regex( + regex, file) + + class ArchInfo: + + def __init__(self): + self.arch = Mach.Arch(0, 0) + self.offset = 0 + self.size = 0 + self.align = 0 + self.mach = None + + def unpack(self, data): + # Universal headers are always in big endian + data.set_byte_order('big') + self.arch.cpu, self.arch.sub, self.offset, self.size, self.align = data.get_n_uint32( + 5) + + def dump_header(self, dump_description=True, options=None): + if options.verbose: + print "CPU SUBTYPE OFFSET SIZE ALIGN" + print "---------- ---------- ---------- ---------- ----------" + else: + print "ARCH FILEOFFSET FILESIZE ALIGN" + print "---------- ---------- ---------- ----------" + + def dump_flat(self, options): + if options.verbose: + print "%#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align) + else: + print "%-10s %#8.8x %#8.8x %#8.8x" % (self.arch, self.offset, self.size, self.align) + + def dump(self): + print " cputype: %#8.8x" % self.arch.cpu + print "cpusubtype: %#8.8x" % self.arch.sub + print " offset: %#8.8x" % self.offset + print " size: %#8.8x" % self.size + print " align: %#8.8x" % self.align + + def __str__(self): + return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % ( + self.arch.cpu, self.arch.sub, self.offset, self.size, self.align) + + def __repr__(self): + return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % ( + self.arch.cpu, self.arch.sub, self.offset, self.size, self.align) + + class Flags: + + def __init__(self, b): + self.bits = b + + def __str__(self): + s = '' + if self.bits & MH_NOUNDEFS: + s += 'MH_NOUNDEFS | ' + if self.bits & MH_INCRLINK: + s += 'MH_INCRLINK | ' + if self.bits & MH_DYLDLINK: + s += 'MH_DYLDLINK | ' + if self.bits & MH_BINDATLOAD: + s += 'MH_BINDATLOAD | ' + if self.bits & MH_PREBOUND: + s += 'MH_PREBOUND | ' + if self.bits & MH_SPLIT_SEGS: + s += 'MH_SPLIT_SEGS | ' + if self.bits & MH_LAZY_INIT: + s += 'MH_LAZY_INIT | ' + if self.bits & MH_TWOLEVEL: + s += 'MH_TWOLEVEL | ' + if self.bits & MH_FORCE_FLAT: + s += 'MH_FORCE_FLAT | ' + if self.bits & MH_NOMULTIDEFS: + s += 'MH_NOMULTIDEFS | ' + if self.bits & MH_NOFIXPREBINDING: + s += 'MH_NOFIXPREBINDING | ' + if self.bits & MH_PREBINDABLE: + s += 'MH_PREBINDABLE | ' + if self.bits & MH_ALLMODSBOUND: + s += 'MH_ALLMODSBOUND | ' + if self.bits & MH_SUBSECTIONS_VIA_SYMBOLS: + s += 'MH_SUBSECTIONS_VIA_SYMBOLS | ' + if self.bits & MH_CANONICAL: + s += 'MH_CANONICAL | ' + if self.bits & MH_WEAK_DEFINES: + s += 'MH_WEAK_DEFINES | ' + if self.bits & MH_BINDS_TO_WEAK: + s += 'MH_BINDS_TO_WEAK | ' + if self.bits & MH_ALLOW_STACK_EXECUTION: + s += 'MH_ALLOW_STACK_EXECUTION | ' + if self.bits & MH_ROOT_SAFE: + s += 'MH_ROOT_SAFE | ' + if self.bits & MH_SETUID_SAFE: + s += 'MH_SETUID_SAFE | ' + if self.bits & MH_NO_REEXPORTED_DYLIBS: + s += 'MH_NO_REEXPORTED_DYLIBS | ' + if self.bits & MH_PIE: + s += 'MH_PIE | ' + if self.bits & MH_DEAD_STRIPPABLE_DYLIB: + s += 'MH_DEAD_STRIPPABLE_DYLIB | ' + if self.bits & MH_HAS_TLV_DESCRIPTORS: + s += 'MH_HAS_TLV_DESCRIPTORS | ' + if self.bits & MH_NO_HEAP_EXECUTION: + s += 'MH_NO_HEAP_EXECUTION | ' + # Strip the trailing " |" if we have any flags + if len(s) > 0: + s = s[0:-2] + return s + + class FileType(dict_utils.Enum): + + enum = { + 'MH_OBJECT': MH_OBJECT, + 'MH_EXECUTE': MH_EXECUTE, + 'MH_FVMLIB': MH_FVMLIB, + 'MH_CORE': MH_CORE, + 'MH_PRELOAD': MH_PRELOAD, + 'MH_DYLIB': MH_DYLIB, + 'MH_DYLINKER': MH_DYLINKER, + 'MH_BUNDLE': MH_BUNDLE, + 'MH_DYLIB_STUB': MH_DYLIB_STUB, + 'MH_DSYM': MH_DSYM, + 'MH_KEXT_BUNDLE': MH_KEXT_BUNDLE + } + + def __init__(self, initial_value=0): + dict_utils.Enum.__init__(self, initial_value, self.enum) + + class Skinny: + + def __init__(self, path): + self.path = path + self.type = 'skinny' + self.data = None + self.file_off = 0 + self.magic = 0 + self.arch = Mach.Arch(0, 0) + self.filetype = Mach.FileType(0) + self.ncmds = 0 + self.sizeofcmds = 0 + self.flags = Mach.Flags(0) + self.uuid = None + self.commands = list() + self.segments = list() + self.sections = list() + self.symbols = list() + self.sections.append(Mach.Section()) + + def description(self): + return '%#8.8x: %s (%s)' % (self.file_off, self.path, self.arch) + + def unpack(self, data, magic=None): + self.data = data + self.file_off = data.tell() + if magic is None: + self.magic = Mach.Magic() + self.magic.unpack(data) + else: + self.magic = magic + self.file_off = self.file_off - 4 + data.set_byte_order(self.magic.get_byte_order()) + self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, bits = data.get_n_uint32( + 6) + self.flags.bits = bits + + if self.is_64_bit(): + data.get_uint32() # Skip reserved word in mach_header_64 + + for i in range(0, self.ncmds): + lc = self.unpack_load_command(data) + self.commands.append(lc) + + def get_data(self): + if self.data: + self.data.set_byte_order(self.magic.get_byte_order()) + return self.data + return None + + def unpack_load_command(self, data): + lc = Mach.LoadCommand() + lc.unpack(self, data) + lc_command = lc.command.get_enum_value() + if (lc_command == LC_SEGMENT or + lc_command == LC_SEGMENT_64): + lc = Mach.SegmentLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_LOAD_DYLIB or + lc_command == LC_ID_DYLIB or + lc_command == LC_LOAD_WEAK_DYLIB or + lc_command == LC_REEXPORT_DYLIB): + lc = Mach.DylibLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_LOAD_DYLINKER or + lc_command == LC_SUB_FRAMEWORK or + lc_command == LC_SUB_CLIENT or + lc_command == LC_SUB_UMBRELLA or + lc_command == LC_SUB_LIBRARY or + lc_command == LC_ID_DYLINKER or + lc_command == LC_RPATH): + lc = Mach.LoadDYLDLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_DYLD_INFO_ONLY): + lc = Mach.DYLDInfoOnlyLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_SYMTAB): + lc = Mach.SymtabLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_DYSYMTAB): + lc = Mach.DYLDSymtabLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_UUID): + lc = Mach.UUIDLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_CODE_SIGNATURE or + lc_command == LC_SEGMENT_SPLIT_INFO or + lc_command == LC_FUNCTION_STARTS): + lc = Mach.DataBlobLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_UNIXTHREAD): + lc = Mach.UnixThreadLoadCommand(lc) + lc.unpack(self, data) + elif (lc_command == LC_ENCRYPTION_INFO): + lc = Mach.EncryptionInfoLoadCommand(lc) + lc.unpack(self, data) + lc.skip(data) + return lc + + def compare(self, rhs): + print "\nComparing:" + print "a) %s %s" % (self.arch, self.path) + print "b) %s %s" % (rhs.arch, rhs.path) + result = True + if self.type == rhs.type: + for lhs_section in self.sections[1:]: + rhs_section = rhs.get_section_by_section(lhs_section) + if rhs_section: + print 'comparing %s.%s...' % (lhs_section.segname, lhs_section.sectname), + sys.stdout.flush() + lhs_data = lhs_section.get_contents(self) + rhs_data = rhs_section.get_contents(rhs) + if lhs_data and rhs_data: + if lhs_data == rhs_data: + print 'ok' + else: + lhs_data_len = len(lhs_data) + rhs_data_len = len(rhs_data) + # if lhs_data_len < rhs_data_len: + # if lhs_data == rhs_data[0:lhs_data_len]: + # print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len) + # else: + # # TODO: check padding + # result = False + # elif lhs_data_len > rhs_data_len: + # if lhs_data[0:rhs_data_len] == rhs_data: + # print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len) + # else: + # # TODO: check padding + # result = False + # else: + result = False + print 'error: sections differ' + # print 'a) %s' % (lhs_section) + # dump_hex_byte_string_diff(0, lhs_data, rhs_data) + # print 'b) %s' % (rhs_section) + # dump_hex_byte_string_diff(0, rhs_data, lhs_data) + elif lhs_data and not rhs_data: + print 'error: section data missing from b:' + print 'a) %s' % (lhs_section) + print 'b) %s' % (rhs_section) + result = False + elif not lhs_data and rhs_data: + print 'error: section data missing from a:' + print 'a) %s' % (lhs_section) + print 'b) %s' % (rhs_section) + result = False + elif lhs_section.offset or rhs_section.offset: + print 'error: section data missing for both a and b:' + print 'a) %s' % (lhs_section) + print 'b) %s' % (rhs_section) + result = False + else: + print 'ok' + else: + result = False + print 'error: section %s is missing in %s' % (lhs_section.sectname, rhs.path) + else: + print 'error: comaparing a %s mach-o file with a %s mach-o file is not supported' % (self.type, rhs.type) + result = False + if not result: + print 'error: mach files differ' + return result + + def dump_header(self, dump_description=True, options=None): + if options.verbose: + print "MAGIC CPU SUBTYPE FILETYPE NUM CMDS SIZE CMDS FLAGS" + print "---------- ---------- ---------- ---------- -------- ---------- ----------" + else: + print "MAGIC ARCH FILETYPE NUM CMDS SIZE CMDS FLAGS" + print "------------ ---------- -------------- -------- ---------- ----------" + + def dump_flat(self, options): + if options.verbose: + print "%#8.8x %#8.8x %#8.8x %#8.8x %#8u %#8.8x %#8.8x" % (self.magic, self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, self.flags.bits) + else: + print "%-12s %-10s %-14s %#8u %#8.8x %s" % (self.magic, self.arch, self.filetype, self.ncmds, self.sizeofcmds, self.flags) + + def dump(self, options): + if options.dump_header: + self.dump_header(True, options) + if options.dump_load_commands: + self.dump_load_commands(False, options) + if options.dump_sections: + self.dump_sections(False, options) + if options.section_names: + self.dump_section_contents(options) + if options.dump_symtab: + self.get_symtab() + if len(self.symbols): + self.dump_sections(False, options) + else: + print "No symbols" + if options.find_mangled: + self.dump_symbol_names_matching_regex(re.compile('^_?_Z')) + + def dump_header(self, dump_description=True, options=None): + if dump_description: + print self.description() + print "Mach Header" + print " magic: %#8.8x %s" % (self.magic.value, self.magic) + print " cputype: %#8.8x %s" % (self.arch.cpu, self.arch) + print " cpusubtype: %#8.8x" % self.arch.sub + print " filetype: %#8.8x %s" % (self.filetype.get_enum_value(), self.filetype.get_enum_name()) + print " ncmds: %#8.8x %u" % (self.ncmds, self.ncmds) + print " sizeofcmds: %#8.8x" % self.sizeofcmds + print " flags: %#8.8x %s" % (self.flags.bits, self.flags) + + def dump_load_commands(self, dump_description=True, options=None): + if dump_description: + print self.description() + for lc in self.commands: + print lc + + def get_section_by_name(self, name): + for section in self.sections: + if section.sectname and section.sectname == name: + return section + return None + + def get_section_by_section(self, other_section): + for section in self.sections: + if section.sectname == other_section.sectname and section.segname == other_section.segname: + return section + return None + + def dump_sections(self, dump_description=True, options=None): + if dump_description: + print self.description() + num_sections = len(self.sections) + if num_sections > 1: + self.sections[1].dump_header() + for sect_idx in range(1, num_sections): + print "%s" % self.sections[sect_idx] + + def dump_section_contents(self, options): + saved_section_to_disk = False + for sectname in options.section_names: + section = self.get_section_by_name(sectname) + if section: + sect_bytes = section.get_contents(self) + if options.outfile: + if not saved_section_to_disk: + outfile = open(options.outfile, 'w') + if options.extract_modules: + # print "Extracting modules from mach file..." + data = file_extract.FileExtract( + StringIO.StringIO(sect_bytes), self.data.byte_order) + version = data.get_uint32() + num_modules = data.get_uint32() + # print "version = %u, num_modules = %u" % + # (version, num_modules) + for i in range(num_modules): + data_offset = data.get_uint64() + data_size = data.get_uint64() + name_offset = data.get_uint32() + language = data.get_uint32() + flags = data.get_uint32() + data.seek(name_offset) + module_name = data.get_c_string() + # print "module[%u] data_offset = %#16.16x, + # data_size = %#16.16x, name_offset = + # %#16.16x (%s), language = %u, flags = + # %#x" % (i, data_offset, data_size, + # name_offset, module_name, language, + # flags) + data.seek(data_offset) + outfile.write(data.read_size(data_size)) + else: + print "Saving section %s to '%s'" % (sectname, options.outfile) + outfile.write(sect_bytes) + outfile.close() + saved_section_to_disk = True + else: + print "error: you can only save a single section to disk at a time, skipping section '%s'" % (sectname) + else: + print 'section %s:\n' % (sectname) + section.dump_header() + print '%s\n' % (section) + dump_memory(0, sect_bytes, options.max_count, 16) + else: + print 'error: no section named "%s" was found' % (sectname) + + def get_segment(self, segname): + if len(self.segments) == 1 and self.segments[0].segname == '': + return self.segments[0] + for segment in self.segments: + if segment.segname == segname: + return segment + return None + + def get_first_load_command(self, lc_enum_value): + for lc in self.commands: + if lc.command.value == lc_enum_value: + return lc + return None + + def get_symtab(self): + if self.data and not self.symbols: + lc_symtab = self.get_first_load_command(LC_SYMTAB) + if lc_symtab: + symtab_offset = self.file_off + if self.data.is_in_memory(): + linkedit_segment = self.get_segment('__LINKEDIT') + if linkedit_segment: + linkedit_vmaddr = linkedit_segment.vmaddr + linkedit_fileoff = linkedit_segment.fileoff + symtab_offset = linkedit_vmaddr + lc_symtab.symoff - linkedit_fileoff + symtab_offset = linkedit_vmaddr + lc_symtab.stroff - linkedit_fileoff + else: + symtab_offset += lc_symtab.symoff + + self.data.seek(symtab_offset) + is_64 = self.is_64_bit() + for i in range(lc_symtab.nsyms): + nlist = Mach.NList() + nlist.unpack(self, self.data, lc_symtab) + self.symbols.append(nlist) + else: + print "no LC_SYMTAB" + + def dump_symtab(self, dump_description=True, options=None): + self.get_symtab() + if dump_description: + print self.description() + for i, symbol in enumerate(self.symbols): + print '[%5u] %s' % (i, symbol) + + def dump_symbol_names_matching_regex(self, regex, file=None): + self.get_symtab() + for symbol in self.symbols: + if symbol.name and regex.search(symbol.name): + print symbol.name + if file: + file.write('%s\n' % (symbol.name)) + + def is_64_bit(self): + return self.magic.is_64_bit() + + class LoadCommand: + + class Command(dict_utils.Enum): + enum = { + 'LC_SEGMENT': LC_SEGMENT, + 'LC_SYMTAB': LC_SYMTAB, + 'LC_SYMSEG': LC_SYMSEG, + 'LC_THREAD': LC_THREAD, + 'LC_UNIXTHREAD': LC_UNIXTHREAD, + 'LC_LOADFVMLIB': LC_LOADFVMLIB, + 'LC_IDFVMLIB': LC_IDFVMLIB, + 'LC_IDENT': LC_IDENT, + 'LC_FVMFILE': LC_FVMFILE, + 'LC_PREPAGE': LC_PREPAGE, + 'LC_DYSYMTAB': LC_DYSYMTAB, + 'LC_LOAD_DYLIB': LC_LOAD_DYLIB, + 'LC_ID_DYLIB': LC_ID_DYLIB, + 'LC_LOAD_DYLINKER': LC_LOAD_DYLINKER, + 'LC_ID_DYLINKER': LC_ID_DYLINKER, + 'LC_PREBOUND_DYLIB': LC_PREBOUND_DYLIB, + 'LC_ROUTINES': LC_ROUTINES, + 'LC_SUB_FRAMEWORK': LC_SUB_FRAMEWORK, + 'LC_SUB_UMBRELLA': LC_SUB_UMBRELLA, + 'LC_SUB_CLIENT': LC_SUB_CLIENT, + 'LC_SUB_LIBRARY': LC_SUB_LIBRARY, + 'LC_TWOLEVEL_HINTS': LC_TWOLEVEL_HINTS, + 'LC_PREBIND_CKSUM': LC_PREBIND_CKSUM, + 'LC_LOAD_WEAK_DYLIB': LC_LOAD_WEAK_DYLIB, + 'LC_SEGMENT_64': LC_SEGMENT_64, + 'LC_ROUTINES_64': LC_ROUTINES_64, + 'LC_UUID': LC_UUID, + 'LC_RPATH': LC_RPATH, + 'LC_CODE_SIGNATURE': LC_CODE_SIGNATURE, + 'LC_SEGMENT_SPLIT_INFO': LC_SEGMENT_SPLIT_INFO, + 'LC_REEXPORT_DYLIB': LC_REEXPORT_DYLIB, + 'LC_LAZY_LOAD_DYLIB': LC_LAZY_LOAD_DYLIB, + 'LC_ENCRYPTION_INFO': LC_ENCRYPTION_INFO, + 'LC_DYLD_INFO': LC_DYLD_INFO, + 'LC_DYLD_INFO_ONLY': LC_DYLD_INFO_ONLY, + 'LC_LOAD_UPWARD_DYLIB': LC_LOAD_UPWARD_DYLIB, + 'LC_VERSION_MIN_MACOSX': LC_VERSION_MIN_MACOSX, + 'LC_VERSION_MIN_IPHONEOS': LC_VERSION_MIN_IPHONEOS, + 'LC_FUNCTION_STARTS': LC_FUNCTION_STARTS, + 'LC_DYLD_ENVIRONMENT': LC_DYLD_ENVIRONMENT + } + + def __init__(self, initial_value=0): + dict_utils.Enum.__init__(self, initial_value, self.enum) + + def __init__(self, c=None, l=0, o=0): + if c is not None: + self.command = c + else: + self.command = Mach.LoadCommand.Command(0) + self.length = l + self.file_off = o + + def unpack(self, mach_file, data): + self.file_off = data.tell() + self.command.value, self.length = data.get_n_uint32(2) + + def skip(self, data): + data.seek(self.file_off + self.length, 0) + + def __str__(self): + lc_name = self.command.get_enum_name() + return '%#8.8x: <%#4.4x> %-24s' % (self.file_off, + self.length, lc_name) + + class Section: + + def __init__(self): + self.index = 0 + self.is_64 = False + self.sectname = None + self.segname = None + self.addr = 0 + self.size = 0 + self.offset = 0 + self.align = 0 + self.reloff = 0 + self.nreloc = 0 + self.flags = 0 + self.reserved1 = 0 + self.reserved2 = 0 + self.reserved3 = 0 + + def unpack(self, is_64, data): + self.is_64 = is_64 + self.sectname = data.get_fixed_length_c_string(16, '', True) + self.segname = data.get_fixed_length_c_string(16, '', True) + if self.is_64: + self.addr, self.size = data.get_n_uint64(2) + self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3 = data.get_n_uint32( + 8) + else: + self.addr, self.size = data.get_n_uint32(2) + self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2 = data.get_n_uint32( + 7) + + def dump_header(self): + if self.is_64: + print "INDEX ADDRESS SIZE OFFSET ALIGN RELOFF NRELOC FLAGS RESERVED1 RESERVED2 RESERVED3 NAME" + print "===== ------------------ ------------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------" + else: + print "INDEX ADDRESS SIZE OFFSET ALIGN RELOFF NRELOC FLAGS RESERVED1 RESERVED2 NAME" + print "===== ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------" + + def __str__(self): + if self.is_64: + return "[%3u] %#16.16x %#16.16x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % ( + self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3, self.segname, self.sectname) + else: + return "[%3u] %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % ( + self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.segname, self.sectname) + + def get_contents(self, mach_file): + '''Get the section contents as a python string''' + if self.size > 0 and mach_file.get_segment( + self.segname).filesize > 0: + data = mach_file.get_data() + if data: + section_data_offset = mach_file.file_off + self.offset + # print '%s.%s is at offset 0x%x with size 0x%x' % + # (self.segname, self.sectname, section_data_offset, + # self.size) + data.push_offset_and_seek(section_data_offset) + bytes = data.read_size(self.size) + data.pop_offset_and_seek() + return bytes + return None + + class DylibLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.name = None + self.timestamp = 0 + self.current_version = 0 + self.compatibility_version = 0 + + def unpack(self, mach_file, data): + byte_order_char = mach_file.magic.get_byte_order() + name_offset, self.timestamp, self.current_version, self.compatibility_version = data.get_n_uint32( + 4) + data.seek(self.file_off + name_offset, 0) + self.name = data.get_fixed_length_c_string(self.length - 24) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += "%#8.8x %#8.8x %#8.8x " % (self.timestamp, + self.current_version, + self.compatibility_version) + s += self.name + return s + + class LoadDYLDLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.name = None + + def unpack(self, mach_file, data): + data.get_uint32() + self.name = data.get_fixed_length_c_string(self.length - 12) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += "%s" % self.name + return s + + class UnixThreadLoadCommand(LoadCommand): + + class ThreadState: + + def __init__(self): + self.flavor = 0 + self.count = 0 + self.register_values = list() + + def unpack(self, data): + self.flavor, self.count = data.get_n_uint32(2) + self.register_values = data.get_n_uint32(self.count) + + def __str__(self): + s = "flavor = %u, count = %u, regs =" % ( + self.flavor, self.count) + i = 0 + for register_value in self.register_values: + if i % 8 == 0: + s += "\n " + s += " %#8.8x" % register_value + i += 1 + return s + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.reg_sets = list() + + def unpack(self, mach_file, data): + reg_set = Mach.UnixThreadLoadCommand.ThreadState() + reg_set.unpack(data) + self.reg_sets.append(reg_set) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + for reg_set in self.reg_sets: + s += "%s" % reg_set + return s + + class DYLDInfoOnlyLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.rebase_off = 0 + self.rebase_size = 0 + self.bind_off = 0 + self.bind_size = 0 + self.weak_bind_off = 0 + self.weak_bind_size = 0 + self.lazy_bind_off = 0 + self.lazy_bind_size = 0 + self.export_off = 0 + self.export_size = 0 + + def unpack(self, mach_file, data): + byte_order_char = mach_file.magic.get_byte_order() + self.rebase_off, self.rebase_size, self.bind_off, self.bind_size, self.weak_bind_off, self.weak_bind_size, self.lazy_bind_off, self.lazy_bind_size, self.export_off, self.export_size = data.get_n_uint32( + 10) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += "rebase_off = %#8.8x, rebase_size = %u, " % ( + self.rebase_off, self.rebase_size) + s += "bind_off = %#8.8x, bind_size = %u, " % ( + self.bind_off, self.bind_size) + s += "weak_bind_off = %#8.8x, weak_bind_size = %u, " % ( + self.weak_bind_off, self.weak_bind_size) + s += "lazy_bind_off = %#8.8x, lazy_bind_size = %u, " % ( + self.lazy_bind_off, self.lazy_bind_size) + s += "export_off = %#8.8x, export_size = %u, " % ( + self.export_off, self.export_size) + return s + + class DYLDSymtabLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.ilocalsym = 0 + self.nlocalsym = 0 + self.iextdefsym = 0 + self.nextdefsym = 0 + self.iundefsym = 0 + self.nundefsym = 0 + self.tocoff = 0 + self.ntoc = 0 + self.modtaboff = 0 + self.nmodtab = 0 + self.extrefsymoff = 0 + self.nextrefsyms = 0 + self.indirectsymoff = 0 + self.nindirectsyms = 0 + self.extreloff = 0 + self.nextrel = 0 + self.locreloff = 0 + self.nlocrel = 0 + + def unpack(self, mach_file, data): + byte_order_char = mach_file.magic.get_byte_order() + self.ilocalsym, self.nlocalsym, self.iextdefsym, self.nextdefsym, self.iundefsym, self.nundefsym, self.tocoff, self.ntoc, self.modtaboff, self.nmodtab, self.extrefsymoff, self.nextrefsyms, self.indirectsymoff, self.nindirectsyms, self.extreloff, self.nextrel, self.locreloff, self.nlocrel = data.get_n_uint32( + 18) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + # s += "ilocalsym = %u, nlocalsym = %u, " % (self.ilocalsym, self.nlocalsym) + # s += "iextdefsym = %u, nextdefsym = %u, " % (self.iextdefsym, self.nextdefsym) + # s += "iundefsym %u, nundefsym = %u, " % (self.iundefsym, self.nundefsym) + # s += "tocoff = %#8.8x, ntoc = %u, " % (self.tocoff, self.ntoc) + # s += "modtaboff = %#8.8x, nmodtab = %u, " % (self.modtaboff, self.nmodtab) + # s += "extrefsymoff = %#8.8x, nextrefsyms = %u, " % (self.extrefsymoff, self.nextrefsyms) + # s += "indirectsymoff = %#8.8x, nindirectsyms = %u, " % (self.indirectsymoff, self.nindirectsyms) + # s += "extreloff = %#8.8x, nextrel = %u, " % (self.extreloff, self.nextrel) + # s += "locreloff = %#8.8x, nlocrel = %u" % (self.locreloff, + # self.nlocrel) + s += "ilocalsym = %-10u, nlocalsym = %u\n" % ( + self.ilocalsym, self.nlocalsym) + s += " iextdefsym = %-10u, nextdefsym = %u\n" % ( + self.iextdefsym, self.nextdefsym) + s += " iundefsym = %-10u, nundefsym = %u\n" % ( + self.iundefsym, self.nundefsym) + s += " tocoff = %#8.8x, ntoc = %u\n" % ( + self.tocoff, self.ntoc) + s += " modtaboff = %#8.8x, nmodtab = %u\n" % ( + self.modtaboff, self.nmodtab) + s += " extrefsymoff = %#8.8x, nextrefsyms = %u\n" % ( + self.extrefsymoff, self.nextrefsyms) + s += " indirectsymoff = %#8.8x, nindirectsyms = %u\n" % ( + self.indirectsymoff, self.nindirectsyms) + s += " extreloff = %#8.8x, nextrel = %u\n" % ( + self.extreloff, self.nextrel) + s += " locreloff = %#8.8x, nlocrel = %u" % ( + self.locreloff, self.nlocrel) + return s + + class SymtabLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.symoff = 0 + self.nsyms = 0 + self.stroff = 0 + self.strsize = 0 + + def unpack(self, mach_file, data): + byte_order_char = mach_file.magic.get_byte_order() + self.symoff, self.nsyms, self.stroff, self.strsize = data.get_n_uint32( + 4) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += "symoff = %#8.8x, nsyms = %u, stroff = %#8.8x, strsize = %u" % ( + self.symoff, self.nsyms, self.stroff, self.strsize) + return s + + class UUIDLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.uuid = None + + def unpack(self, mach_file, data): + uuid_data = data.get_n_uint8(16) + uuid_str = '' + for byte in uuid_data: + uuid_str += '%2.2x' % byte + self.uuid = uuid.UUID(uuid_str) + mach_file.uuid = self.uuid + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += self.uuid.__str__() + return s + + class DataBlobLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.dataoff = 0 + self.datasize = 0 + + def unpack(self, mach_file, data): + byte_order_char = mach_file.magic.get_byte_order() + self.dataoff, self.datasize = data.get_n_uint32(2) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += "dataoff = %#8.8x, datasize = %u" % ( + self.dataoff, self.datasize) + return s + + class EncryptionInfoLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.cryptoff = 0 + self.cryptsize = 0 + self.cryptid = 0 + + def unpack(self, mach_file, data): + byte_order_char = mach_file.magic.get_byte_order() + self.cryptoff, self.cryptsize, self.cryptid = data.get_n_uint32(3) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + s += "file-range = [%#8.8x - %#8.8x), cryptsize = %u, cryptid = %u" % ( + self.cryptoff, self.cryptoff + self.cryptsize, self.cryptsize, self.cryptid) + return s + + class SegmentLoadCommand(LoadCommand): + + def __init__(self, lc): + Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) + self.segname = None + self.vmaddr = 0 + self.vmsize = 0 + self.fileoff = 0 + self.filesize = 0 + self.maxprot = 0 + self.initprot = 0 + self.nsects = 0 + self.flags = 0 + + def unpack(self, mach_file, data): + is_64 = self.command.get_enum_value() == LC_SEGMENT_64 + self.segname = data.get_fixed_length_c_string(16, '', True) + if is_64: + self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint64( + 4) + else: + self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint32( + 4) + self.maxprot, self.initprot, self.nsects, self.flags = data.get_n_uint32( + 4) + mach_file.segments.append(self) + for i in range(self.nsects): + section = Mach.Section() + section.unpack(is_64, data) + section.index = len(mach_file.sections) + mach_file.sections.append(section) + + def __str__(self): + s = Mach.LoadCommand.__str__(self) + if self.command.get_enum_value() == LC_SEGMENT: + s += "%#8.8x %#8.8x %#8.8x %#8.8x " % ( + self.vmaddr, self.vmsize, self.fileoff, self.filesize) + else: + s += "%#16.16x %#16.16x %#16.16x %#16.16x " % ( + self.vmaddr, self.vmsize, self.fileoff, self.filesize) + s += "%s %s %3u %#8.8x" % (vm_prot_names[self.maxprot], vm_prot_names[ + self.initprot], self.nsects, self.flags) + s += ' ' + self.segname + return s + + class NList: + + class Type: + + class Stab(dict_utils.Enum): + enum = { + 'N_GSYM': N_GSYM, + 'N_FNAME': N_FNAME, + 'N_FUN': N_FUN, + 'N_STSYM': N_STSYM, + 'N_LCSYM': N_LCSYM, + 'N_BNSYM': N_BNSYM, + 'N_OPT': N_OPT, + 'N_RSYM': N_RSYM, + 'N_SLINE': N_SLINE, + 'N_ENSYM': N_ENSYM, + 'N_SSYM': N_SSYM, + 'N_SO': N_SO, + 'N_OSO': N_OSO, + 'N_LSYM': N_LSYM, + 'N_BINCL': N_BINCL, + 'N_SOL': N_SOL, + 'N_PARAMS': N_PARAMS, + 'N_VERSION': N_VERSION, + 'N_OLEVEL': N_OLEVEL, + 'N_PSYM': N_PSYM, + 'N_EINCL': N_EINCL, + 'N_ENTRY': N_ENTRY, + 'N_LBRAC': N_LBRAC, + 'N_EXCL': N_EXCL, + 'N_RBRAC': N_RBRAC, + 'N_BCOMM': N_BCOMM, + 'N_ECOMM': N_ECOMM, + 'N_ECOML': N_ECOML, + 'N_LENG': N_LENG + } + + def __init__(self, magic=0): + dict_utils.Enum.__init__(self, magic, self.enum) + + def __init__(self, t=0): + self.value = t + + def __str__(self): + n_type = self.value + if n_type & N_STAB: + stab = Mach.NList.Type.Stab(self.value) + return '%s' % stab + else: + type = self.value & N_TYPE + type_str = '' + if type == N_UNDF: + type_str = 'N_UNDF' + elif type == N_ABS: + type_str = 'N_ABS ' + elif type == N_SECT: + type_str = 'N_SECT' + elif type == N_PBUD: + type_str = 'N_PBUD' + elif type == N_INDR: + type_str = 'N_INDR' + else: + type_str = "??? (%#2.2x)" % type + if n_type & N_PEXT: + type_str += ' | PEXT' + if n_type & N_EXT: + type_str += ' | EXT ' + return type_str + + def __init__(self): + self.index = 0 + self.name_offset = 0 + self.name = 0 + self.type = Mach.NList.Type() + self.sect_idx = 0 + self.desc = 0 + self.value = 0 + + def unpack(self, mach_file, data, symtab_lc): + self.index = len(mach_file.symbols) + self.name_offset = data.get_uint32() + self.type.value, self.sect_idx = data.get_n_uint8(2) + self.desc = data.get_uint16() + if mach_file.is_64_bit(): + self.value = data.get_uint64() + else: + self.value = data.get_uint32() + data.push_offset_and_seek( + mach_file.file_off + + symtab_lc.stroff + + self.name_offset) + # print "get string for symbol[%u]" % self.index + self.name = data.get_c_string() + data.pop_offset_and_seek() + + def __str__(self): + name_display = '' + if len(self.name): + name_display = ' "%s"' % self.name + return '%#8.8x %#2.2x (%-20s) %#2.2x %#4.4x %16.16x%s' % (self.name_offset, + self.type.value, self.type, self.sect_idx, self.desc, self.value, name_display) + + class Interactive(cmd.Cmd): + '''Interactive command interpreter to mach-o files.''' + + def __init__(self, mach, options): + cmd.Cmd.__init__(self) + self.intro = 'Interactive mach-o command interpreter' + self.prompt = 'mach-o: %s %% ' % mach.path + self.mach = mach + self.options = options + + def default(self, line): + '''Catch all for unknown command, which will exit the interpreter.''' + print "uknown command: %s" % line + return True + + def do_q(self, line): + '''Quit command''' + return True + + def do_quit(self, line): + '''Quit command''' + return True + + def do_header(self, line): + '''Dump mach-o file headers''' + self.mach.dump_header(True, self.options) + return False + + def do_load(self, line): + '''Dump all mach-o load commands''' + self.mach.dump_load_commands(True, self.options) + return False + + def do_sections(self, line): + '''Dump all mach-o sections''' + self.mach.dump_sections(True, self.options) + return False + + def do_symtab(self, line): + '''Dump all mach-o symbols in the symbol table''' + self.mach.dump_symtab(True, self.options) + return False + +if __name__ == '__main__': + parser = optparse.OptionParser( + description='A script that parses skinny and universal mach-o files.') + parser.add_option( + '--arch', + '-a', + type='string', + metavar='arch', + dest='archs', + action='append', + help='specify one or more architectures by name') + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + parser.add_option( + '-H', + '--header', + action='store_true', + dest='dump_header', + help='dump the mach-o file header', + default=False) + parser.add_option( + '-l', + '--load-commands', + action='store_true', + dest='dump_load_commands', + help='dump the mach-o load commands', + default=False) + parser.add_option( + '-s', + '--symtab', + action='store_true', + dest='dump_symtab', + help='dump the mach-o symbol table', + default=False) + parser.add_option( + '-S', + '--sections', + action='store_true', + dest='dump_sections', + help='dump the mach-o sections', + default=False) + parser.add_option( + '--section', + type='string', + metavar='sectname', + dest='section_names', + action='append', + help='Specify one or more section names to dump', + default=[]) + parser.add_option( + '-o', + '--out', + type='string', + dest='outfile', + help='Used in conjunction with the --section=NAME option to save a single section\'s data to disk.', + default=False) + parser.add_option( + '-i', + '--interactive', + action='store_true', + dest='interactive', + help='enable interactive mode', + default=False) + parser.add_option( + '-m', + '--mangled', + action='store_true', + dest='find_mangled', + help='dump all mangled names in a mach file', + default=False) + parser.add_option( + '-c', + '--compare', + action='store_true', + dest='compare', + help='compare two mach files', + default=False) + parser.add_option( + '-M', + '--extract-modules', + action='store_true', + dest='extract_modules', + help='Extract modules from file', + default=False) + parser.add_option( + '-C', + '--count', + type='int', + dest='max_count', + help='Sets the max byte count when dumping section data', + default=-1) + + (options, mach_files) = parser.parse_args() + if options.extract_modules: + if options.section_names: + print "error: can't use --section option with the --extract-modules option" + exit(1) + if not options.outfile: + print "error: the --output=FILE option must be specified with the --extract-modules option" + exit(1) + options.section_names.append("__apple_ast") + if options.compare: + if len(mach_files) == 2: + mach_a = Mach() + mach_b = Mach() + mach_a.parse(mach_files[0]) + mach_b.parse(mach_files[1]) + mach_a.compare(mach_b) + else: + print 'error: --compare takes two mach files as arguments' + else: + if not (options.dump_header or options.dump_load_commands or options.dump_symtab or options.dump_sections or options.find_mangled or options.section_names): + options.dump_header = True + options.dump_load_commands = True + if options.verbose: + print 'options', options + print 'mach_files', mach_files + for path in mach_files: + mach = Mach() + mach.parse(path) + if options.interactive: + interpreter = Mach.Interactive(mach, options) + interpreter.cmdloop() + else: + mach.dump(options) diff --git a/examples/python/memory.py b/examples/python/memory.py new file mode 100755 index 000000000..5e2f636dc --- /dev/null +++ b/examples/python/memory.py @@ -0,0 +1,276 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# +# # To use this in the embedded python interpreter using "lldb" just +# import it with the full path using the "command script import" +# command +# (lldb) command script import /path/to/cmdtemplate.py +#---------------------------------------------------------------------- + +import commands +import platform +import os +import re +import sys + +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append( + os.path.realpath( + xcode_dir + + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append( + xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append( + '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + +import commands +import optparse +import shlex +import string +import struct +import time + + +def append_data_callback(option, opt_str, value, parser): + if opt_str == "--uint8": + int8 = int(value, 0) + parser.values.data += struct.pack('1B', int8) + if opt_str == "--uint16": + int16 = int(value, 0) + parser.values.data += struct.pack('1H', int16) + if opt_str == "--uint32": + int32 = int(value, 0) + parser.values.data += struct.pack('1I', int32) + if opt_str == "--uint64": + int64 = int(value, 0) + parser.values.data += struct.pack('1Q', int64) + if opt_str == "--int8": + int8 = int(value, 0) + parser.values.data += struct.pack('1b', int8) + if opt_str == "--int16": + int16 = int(value, 0) + parser.values.data += struct.pack('1h', int16) + if opt_str == "--int32": + int32 = int(value, 0) + parser.values.data += struct.pack('1i', int32) + if opt_str == "--int64": + int64 = int(value, 0) + parser.values.data += struct.pack('1q', int64) + + +def create_memfind_options(): + usage = "usage: %prog [options] STARTADDR [ENDADDR]" + description = '''This command can find data in a specified address range. +Options are used to specify the data that is to be looked for and the options +can be specified multiple times to look for longer streams of data. +''' + parser = optparse.OptionParser( + description=description, + prog='memfind', + usage=usage) + parser.add_option( + '-s', + '--size', + type='int', + metavar='BYTESIZE', + dest='size', + help='Specify the byte size to search.', + default=0) + parser.add_option( + '--int8', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 8 bit signed integer value to search for in memory.', + default='') + parser.add_option( + '--int16', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 16 bit signed integer value to search for in memory.', + default='') + parser.add_option( + '--int32', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 32 bit signed integer value to search for in memory.', + default='') + parser.add_option( + '--int64', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 64 bit signed integer value to search for in memory.', + default='') + parser.add_option( + '--uint8', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 8 bit unsigned integer value to search for in memory.', + default='') + parser.add_option( + '--uint16', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 16 bit unsigned integer value to search for in memory.', + default='') + parser.add_option( + '--uint32', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 32 bit unsigned integer value to search for in memory.', + default='') + parser.add_option( + '--uint64', + action="callback", + callback=append_data_callback, + type='string', + metavar='INT', + dest='data', + help='Specify a 64 bit unsigned integer value to search for in memory.', + default='') + return parser + + +def memfind_command(debugger, command, result, dict): + # Use the Shell Lexer to properly parse up command options just like a + # shell would + command_args = shlex.split(command) + parser = create_memfind_options() + (options, args) = parser.parse_args(command_args) + # try: + # (options, args) = parser.parse_args(command_args) + # except: + # # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit + # # (courtesy of OptParse dealing with argument errors by throwing SystemExit) + # result.SetStatus (lldb.eReturnStatusFailed) + # print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string + # return + memfind(debugger.GetSelectedTarget(), options, args, result) + + +def print_error(str, show_usage, result): + print >>result, str + if show_usage: + print >>result, create_memfind_options().format_help() + + +def memfind(target, options, args, result): + num_args = len(args) + start_addr = 0 + if num_args == 1: + if options.size > 0: + print_error( + "error: --size must be specified if there is no ENDADDR argument", + True, + result) + return + start_addr = int(args[0], 0) + elif num_args == 2: + if options.size != 0: + print_error( + "error: --size can't be specified with an ENDADDR argument", + True, + result) + return + start_addr = int(args[0], 0) + end_addr = int(args[1], 0) + if start_addr >= end_addr: + print_error( + "error: inavlid memory range [%#x - %#x)" % + (start_addr, end_addr), True, result) + return + options.size = end_addr - start_addr + else: + print_error("error: memfind takes 1 or 2 arguments", True, result) + return + + if not options.data: + print >>result, 'error: no data specified to search for' + return + + if not target: + print >>result, 'error: invalid target' + return + process = target.process + if not process: + print >>result, 'error: invalid process' + return + + error = lldb.SBError() + bytes = process.ReadMemory(start_addr, options.size, error) + if error.Success(): + num_matches = 0 + print >>result, "Searching memory range [%#x - %#x) for" % ( + start_addr, end_addr), + for byte in options.data: + print >>result, '%2.2x' % ord(byte), + print >>result + + match_index = string.find(bytes, options.data) + while match_index != -1: + num_matches = num_matches + 1 + print >>result, '%#x: %#x + %u' % (start_addr + + match_index, start_addr, match_index) + match_index = string.find(bytes, options.data, match_index + 1) + + if num_matches == 0: + print >>result, "error: no matches found" + else: + print >>result, 'error: %s' % (error.GetCString()) + + +if __name__ == '__main__': + print 'error: this script is designed to be used within the embedded script interpreter in LLDB' +elif getattr(lldb, 'debugger', None): + memfind_command.__doc__ = create_memfind_options().format_help() + lldb.debugger.HandleCommand( + 'command script add -f memory.memfind_command memfind') + print '"memfind" command installed, use the "--help" option for detailed help' diff --git a/examples/python/operating_system.py b/examples/python/operating_system.py new file mode 100644 index 000000000..bfa13f056 --- /dev/null +++ b/examples/python/operating_system.py @@ -0,0 +1,231 @@ +#!/usr/bin/python + +import lldb +import struct + + +class OperatingSystemPlugIn(object): + """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class""" + + def __init__(self, process): + '''Initialization needs a valid.SBProcess object. + + This plug-in will get created after a live process is valid and has stopped for the + first time.''' + self.process = None + self.registers = None + self.threads = None + if isinstance(process, lldb.SBProcess) and process.IsValid(): + self.process = process + self.threads = None # Will be an dictionary containing info for each thread + + def get_target(self): + # NOTE: Don't use "lldb.target" when trying to get your target as the "lldb.target" + # tracks the current target in the LLDB command interpreter which isn't the + # correct thing to use for this plug-in. + return self.process.target + + def create_thread(self, tid, context): + if tid == 0x444444444: + thread_info = { + 'tid': tid, + 'name': 'four', + 'queue': 'queue4', + 'state': 'stopped', + 'stop_reason': 'none'} + self.threads.append(thread_info) + return thread_info + return None + + def get_thread_info(self): + if not self.threads: + # The sample dictionary below shows the values that can be returned for a thread + # tid => thread ID (mandatory) + # name => thread name (optional key/value pair) + # queue => thread dispatch queue name (optional key/value pair) + # state => thred state (mandatory, set to 'stopped' for now) + # stop_reason => thread stop reason. (mandatory, usually set to 'none') + # Possible values include: + # 'breakpoint' if the thread is stopped at a breakpoint + # 'none' thread is just stopped because the process is stopped + # 'trace' the thread just single stepped + # The usual value for this while threads are in memory is 'none' + # register_data_addr => the address of the register data in memory (optional key/value pair) + # Specifying this key/value pair for a thread will avoid a call to get_register_data() + # and can be used when your registers are in a thread context structure that is contiguous + # in memory. Don't specify this if your register layout in memory doesn't match the layout + # described by the dictionary returned from a call to the + # get_register_info() method. + self.threads = [{'tid': 0x111111111, + 'name': 'one', + 'queue': 'queue1', + 'state': 'stopped', + 'stop_reason': 'breakpoint'}, + {'tid': 0x222222222, + 'name': 'two', + 'queue': 'queue2', + 'state': 'stopped', + 'stop_reason': 'none'}, + {'tid': 0x333333333, + 'name': 'three', + 'queue': 'queue3', + 'state': 'stopped', + 'stop_reason': 'trace', + 'register_data_addr': 0x100000000}] + return self.threads + + def get_register_info(self): + if self.registers is None: + self.registers = dict() + triple = self.process.target.triple + if triple: + arch = triple.split('-')[0] + if arch == 'x86_64': + self.registers['sets'] = ['GPR', 'FPU', 'EXC'] + self.registers['registers'] = [ + {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0}, + {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3}, + {'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4', }, + {'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3', }, + {'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1', }, + {'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2', }, + {'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp', }, + {'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp', }, + {'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5', }, + {'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6', }, + {'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10}, + {'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11}, + {'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12}, + {'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13}, + {'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14}, + {'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15}, + {'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'}, + {'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'}, + {'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0}, + {'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0}, + {'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0}, + ] + return self.registers + + def get_register_data(self, tid): + if tid == 0x111111111: + return struct.pack( + '21Q', + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21) + elif tid == 0x222222222: + return struct.pack( + '21Q', + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121) + elif tid == 0x333333333: + return struct.pack( + '21Q', + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221) + elif tid == 0x444444444: + return struct.pack( + '21Q', + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 310, + 311, + 312, + 313, + 314, + 315, + 316, + 317, + 318, + 319, + 320, + 321) + else: + return struct.pack( + '21Q', + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 410, + 411, + 412, + 413, + 414, + 415, + 416, + 417, + 418, + 419, + 420, + 421) + return None diff --git a/examples/python/performance.py b/examples/python/performance.py new file mode 100755 index 000000000..f1bc94f4b --- /dev/null +++ b/examples/python/performance.py @@ -0,0 +1,392 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# On MacOSX csh, tcsh: +# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python +# On MacOSX sh, bash: +# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python +#---------------------------------------------------------------------- + +import commands +import optparse +import os +import platform +import re +import resource +import sys +import time +import types + +#---------------------------------------------------------------------- +# Code that auto imports LLDB +#---------------------------------------------------------------------- +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append( + os.path.realpath( + xcode_dir + + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append( + xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append( + '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + + +class Timer: + + def __enter__(self): + self.start = time.clock() + return self + + def __exit__(self, *args): + self.end = time.clock() + self.interval = self.end - self.start + + +class Action(object): + """Class that encapsulates actions to take when a thread stops for a reason.""" + + def __init__(self, callback=None, callback_owner=None): + self.callback = callback + self.callback_owner = callback_owner + + def ThreadStopped(self, thread): + assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass" + + +class PlanCompleteAction (Action): + + def __init__(self, callback=None, callback_owner=None): + Action.__init__(self, callback, callback_owner) + + def ThreadStopped(self, thread): + if thread.GetStopReason() == lldb.eStopReasonPlanComplete: + if self.callback: + if self.callback_owner: + self.callback(self.callback_owner, thread) + else: + self.callback(thread) + return True + return False + + +class BreakpointAction (Action): + + def __init__( + self, + callback=None, + callback_owner=None, + name=None, + module=None, + file=None, + line=None, + breakpoint=None): + Action.__init__(self, callback, callback_owner) + self.modules = lldb.SBFileSpecList() + self.files = lldb.SBFileSpecList() + self.breakpoints = list() + # "module" can be a list or a string + if breakpoint: + self.breakpoints.append(breakpoint) + else: + if module: + if isinstance(module, types.ListType): + for module_path in module: + self.modules.Append( + lldb.SBFileSpec(module_path, False)) + elif isinstance(module, types.StringTypes): + self.modules.Append(lldb.SBFileSpec(module, False)) + if name: + # "file" can be a list or a string + if file: + if isinstance(file, types.ListType): + self.files = lldb.SBFileSpecList() + for f in file: + self.files.Append(lldb.SBFileSpec(f, False)) + elif isinstance(file, types.StringTypes): + self.files.Append(lldb.SBFileSpec(file, False)) + self.breakpoints.append( + self.target.BreakpointCreateByName( + name, self.modules, self.files)) + elif file and line: + self.breakpoints.append( + self.target.BreakpointCreateByLocation( + file, line)) + + def ThreadStopped(self, thread): + if thread.GetStopReason() == lldb.eStopReasonBreakpoint: + for bp in self.breakpoints: + if bp.GetID() == thread.GetStopReasonDataAtIndex(0): + if self.callback: + if self.callback_owner: + self.callback(self.callback_owner, thread) + else: + self.callback(thread) + return True + return False + + +class TestCase: + """Class that aids in running performance tests.""" + + def __init__(self): + self.verbose = False + self.debugger = lldb.SBDebugger.Create() + self.target = None + self.process = None + self.thread = None + self.launch_info = None + self.done = False + self.listener = self.debugger.GetListener() + self.user_actions = list() + self.builtin_actions = list() + self.bp_id_to_dict = dict() + + def Setup(self, args): + self.launch_info = lldb.SBLaunchInfo(args) + + def Run(self, args): + assert False, "performance.TestCase.Run(self, args) must be subclassed" + + def Launch(self): + if self.target: + error = lldb.SBError() + self.process = self.target.Launch(self.launch_info, error) + if not error.Success(): + print "error: %s" % error.GetCString() + if self.process: + self.process.GetBroadcaster().AddListener(self.listener, + lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt) + return True + return False + + def WaitForNextProcessEvent(self): + event = None + if self.process: + while event is None: + process_event = lldb.SBEvent() + if self.listener.WaitForEvent(lldb.UINT32_MAX, process_event): + state = lldb.SBProcess.GetStateFromEvent(process_event) + if self.verbose: + print "event = %s" % (lldb.SBDebugger.StateAsCString(state)) + if lldb.SBProcess.GetRestartedFromEvent(process_event): + continue + if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited: + event = process_event + self.done = True + elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended: + continue + elif state == lldb.eStateStopped: + event = process_event + call_test_step = True + fatal = False + selected_thread = False + for thread in self.process: + frame = thread.GetFrameAtIndex(0) + select_thread = False + + stop_reason = thread.GetStopReason() + if self.verbose: + print "tid = %#x pc = %#x " % (thread.GetThreadID(), frame.GetPC()), + if stop_reason == lldb.eStopReasonNone: + if self.verbose: + print "none" + elif stop_reason == lldb.eStopReasonTrace: + select_thread = True + if self.verbose: + print "trace" + elif stop_reason == lldb.eStopReasonPlanComplete: + select_thread = True + if self.verbose: + print "plan complete" + elif stop_reason == lldb.eStopReasonThreadExiting: + if self.verbose: + print "thread exiting" + elif stop_reason == lldb.eStopReasonExec: + if self.verbose: + print "exec" + elif stop_reason == lldb.eStopReasonInvalid: + if self.verbose: + print "invalid" + elif stop_reason == lldb.eStopReasonException: + select_thread = True + if self.verbose: + print "exception" + fatal = True + elif stop_reason == lldb.eStopReasonBreakpoint: + select_thread = True + bp_id = thread.GetStopReasonDataAtIndex(0) + bp_loc_id = thread.GetStopReasonDataAtIndex(1) + if self.verbose: + print "breakpoint id = %d.%d" % (bp_id, bp_loc_id) + elif stop_reason == lldb.eStopReasonWatchpoint: + select_thread = True + if self.verbose: + print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0)) + elif stop_reason == lldb.eStopReasonSignal: + select_thread = True + if self.verbose: + print "signal %d" % (thread.GetStopReasonDataAtIndex(0)) + + if select_thread and not selected_thread: + self.thread = thread + selected_thread = self.process.SetSelectedThread( + thread) + + for action in self.user_actions: + action.ThreadStopped(thread) + + if fatal: + # if self.verbose: + # Xcode.RunCommand(self.debugger,"bt all",true) + sys.exit(1) + return event + + +class Measurement: + '''A class that encapsulates a measurement''' + + def __init__(self): + object.__init__(self) + + def Measure(self): + assert False, "performance.Measurement.Measure() must be subclassed" + + +class MemoryMeasurement(Measurement): + '''A class that can measure memory statistics for a process.''' + + def __init__(self, pid): + Measurement.__init__(self) + self.pid = pid + self.stats = [ + "rprvt", + "rshrd", + "rsize", + "vsize", + "vprvt", + "kprvt", + "kshrd", + "faults", + "cow", + "pageins"] + self.command = "top -l 1 -pid %u -stats %s" % ( + self.pid, ",".join(self.stats)) + self.value = dict() + + def Measure(self): + output = commands.getoutput(self.command).split("\n")[-1] + values = re.split('[-+\s]+', output) + for (idx, stat) in enumerate(values): + multiplier = 1 + if stat: + if stat[-1] == 'K': + multiplier = 1024 + stat = stat[:-1] + elif stat[-1] == 'M': + multiplier = 1024 * 1024 + stat = stat[:-1] + elif stat[-1] == 'G': + multiplier = 1024 * 1024 * 1024 + elif stat[-1] == 'T': + multiplier = 1024 * 1024 * 1024 * 1024 + stat = stat[:-1] + self.value[self.stats[idx]] = int(stat) * multiplier + + def __str__(self): + '''Dump the MemoryMeasurement current value''' + s = '' + for key in self.value.keys(): + if s: + s += "\n" + s += "%8s = %s" % (key, self.value[key]) + return s + + +class TesterTestCase(TestCase): + + def __init__(self): + TestCase.__init__(self) + self.verbose = True + self.num_steps = 5 + + def BreakpointHit(self, thread): + bp_id = thread.GetStopReasonDataAtIndex(0) + loc_id = thread.GetStopReasonDataAtIndex(1) + print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id)) + thread.StepOver() + + def PlanComplete(self, thread): + if self.num_steps > 0: + thread.StepOver() + self.num_steps = self.num_steps - 1 + else: + thread.process.Kill() + + def Run(self, args): + self.Setup(args) + with Timer() as total_time: + self.target = self.debugger.CreateTarget(args[0]) + if self.target: + with Timer() as breakpoint_timer: + bp = self.target.BreakpointCreateByName("main") + print( + 'Breakpoint time = %.03f sec.' % + breakpoint_timer.interval) + + self.user_actions.append( + BreakpointAction( + breakpoint=bp, + callback=TesterTestCase.BreakpointHit, + callback_owner=self)) + self.user_actions.append( + PlanCompleteAction( + callback=TesterTestCase.PlanComplete, + callback_owner=self)) + + if self.Launch(): + while not self.done: + self.WaitForNextProcessEvent() + else: + print "error: failed to launch process" + else: + print "error: failed to create target with '%s'" % (args[0]) + print('Total time = %.03f sec.' % total_time.interval) + + +if __name__ == '__main__': + lldb.SBDebugger.Initialize() + test = TesterTestCase() + test.Run(sys.argv[1:]) + mem = MemoryMeasurement(os.getpid()) + mem.Measure() + print str(mem) + lldb.SBDebugger.Terminate() + # print "sleeeping for 100 seconds" + # time.sleep(100) diff --git a/examples/python/process_events.py b/examples/python/process_events.py new file mode 100755 index 000000000..c93020a97 --- /dev/null +++ b/examples/python/process_events.py @@ -0,0 +1,417 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# On MacOSX csh, tcsh: +# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python +# On MacOSX sh, bash: +# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python +#---------------------------------------------------------------------- + +import commands +import optparse +import os +import platform +import sys + +#---------------------------------------------------------------------- +# Code that auto imports LLDB +#---------------------------------------------------------------------- +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append( + os.path.realpath( + xcode_dir + + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append( + xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append( + '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + + +def print_threads(process, options): + if options.show_threads: + for thread in process: + print '%s %s' % (thread, thread.GetFrameAtIndex(0)) + + +def run_commands(command_interpreter, commands): + return_obj = lldb.SBCommandReturnObject() + for command in commands: + command_interpreter.HandleCommand(command, return_obj) + if return_obj.Succeeded(): + print return_obj.GetOutput() + else: + print return_obj + if options.stop_on_error: + break + + +def main(argv): + description = '''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.''' + epilog = '''Examples: + +#---------------------------------------------------------------------- +# Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint +# at "malloc" and backtrace and read all registers each time we stop +#---------------------------------------------------------------------- +% ./process_events.py --breakpoint malloc --stop-command bt --stop-command 'register read' -- /bin/ls -lAF /tmp/ + +''' + optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog + parser = optparse.OptionParser( + description=description, + prog='process_events', + usage='usage: process_events [options] program [arg1 arg2]', + epilog=epilog) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help="Enable verbose logging.", + default=False) + parser.add_option( + '-b', + '--breakpoint', + action='append', + type='string', + metavar='BPEXPR', + dest='breakpoints', + help='Breakpoint commands to create after the target has been created, the values will be sent to the "_regexp-break" command which supports breakpoints by name, file:line, and address.') + parser.add_option( + '-a', + '--arch', + type='string', + dest='arch', + help='The architecture to use when creating the debug target.', + default=None) + parser.add_option( + '--platform', + type='string', + metavar='platform', + dest='platform', + help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".', + default=None) + parser.add_option( + '-l', + '--launch-command', + action='append', + type='string', + metavar='CMD', + dest='launch_commands', + help='LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.', + default=[]) + parser.add_option( + '-s', + '--stop-command', + action='append', + type='string', + metavar='CMD', + dest='stop_commands', + help='LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.', + default=[]) + parser.add_option( + '-c', + '--crash-command', + action='append', + type='string', + metavar='CMD', + dest='crash_commands', + help='LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.', + default=[]) + parser.add_option( + '-x', + '--exit-command', + action='append', + type='string', + metavar='CMD', + dest='exit_commands', + help='LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.', + default=[]) + parser.add_option( + '-T', + '--no-threads', + action='store_false', + dest='show_threads', + help="Don't show threads when process stops.", + default=True) + parser.add_option( + '--ignore-errors', + action='store_false', + dest='stop_on_error', + help="Don't stop executing LLDB commands if the command returns an error. This applies to all of the LLDB command interpreter commands that get run for launch, stop, crash and exit.", + default=True) + parser.add_option( + '-n', + '--run-count', + type='int', + dest='run_count', + metavar='N', + help='How many times to run the process in case the process exits.', + default=1) + parser.add_option( + '-t', + '--event-timeout', + type='int', + dest='event_timeout', + metavar='SEC', + help='Specify the timeout in seconds to wait for process state change events.', + default=lldb.UINT32_MAX) + parser.add_option( + '-e', + '--environment', + action='append', + type='string', + metavar='ENV', + dest='env_vars', + help='Environment variables to set in the inferior process when launching a process.') + parser.add_option( + '-d', + '--working-dir', + type='string', + metavar='DIR', + dest='working_dir', + help='The the current working directory when launching a process.', + default=None) + parser.add_option( + '-p', + '--attach-pid', + type='int', + dest='attach_pid', + metavar='PID', + help='Specify a process to attach to by process ID.', + default=-1) + parser.add_option( + '-P', + '--attach-name', + type='string', + dest='attach_name', + metavar='PROCESSNAME', + help='Specify a process to attach to by name.', + default=None) + parser.add_option( + '-w', + '--attach-wait', + action='store_true', + dest='attach_wait', + help='Wait for the next process to launch when attaching to a process by name.', + default=False) + try: + (options, args) = parser.parse_args(argv) + except: + return + + attach_info = None + launch_info = None + exe = None + if args: + exe = args.pop(0) + launch_info = lldb.SBLaunchInfo(args) + if options.env_vars: + launch_info.SetEnvironmentEntries(options.env_vars, True) + if options.working_dir: + launch_info.SetWorkingDirectory(options.working_dir) + elif options.attach_pid != -1: + if options.run_count == 1: + attach_info = lldb.SBAttachInfo(options.attach_pid) + else: + print "error: --run-count can't be used with the --attach-pid option" + sys.exit(1) + elif not options.attach_name is None: + if options.run_count == 1: + attach_info = lldb.SBAttachInfo( + options.attach_name, options.attach_wait) + else: + print "error: --run-count can't be used with the --attach-name option" + sys.exit(1) + else: + print 'error: a program path for a program to debug and its arguments are required' + sys.exit(1) + + # Create a new debugger instance + debugger = lldb.SBDebugger.Create() + debugger.SetAsync(True) + command_interpreter = debugger.GetCommandInterpreter() + # Create a target from a file and arch + + if exe: + print "Creating a target for '%s'" % exe + error = lldb.SBError() + target = debugger.CreateTarget( + exe, options.arch, options.platform, True, error) + + if target: + + # Set any breakpoints that were specified in the args if we are launching. We use the + # command line command to take advantage of the shorthand breakpoint + # creation + if launch_info and options.breakpoints: + for bp in options.breakpoints: + debugger.HandleCommand("_regexp-break %s" % (bp)) + run_commands(command_interpreter, ['breakpoint list']) + + for run_idx in range(options.run_count): + # Launch the process. Since we specified synchronous mode, we won't return + # from this function until we hit the breakpoint at main + error = lldb.SBError() + + if launch_info: + if options.run_count == 1: + print 'Launching "%s"...' % (exe) + else: + print 'Launching "%s"... (launch %u of %u)' % (exe, run_idx + 1, options.run_count) + + process = target.Launch(launch_info, error) + else: + if options.attach_pid != -1: + print 'Attaching to process %i...' % (options.attach_pid) + else: + if options.attach_wait: + print 'Waiting for next to process named "%s" to launch...' % (options.attach_name) + else: + print 'Attaching to existing process named "%s"...' % (options.attach_name) + process = target.Attach(attach_info, error) + + # Make sure the launch went ok + if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID: + + pid = process.GetProcessID() + print 'Process is %i' % (pid) + if attach_info: + # continue process if we attached as we won't get an + # initial event + process.Continue() + + listener = debugger.GetListener() + # sign up for process state change events + stop_idx = 0 + done = False + while not done: + event = lldb.SBEvent() + if listener.WaitForEvent(options.event_timeout, event): + if lldb.SBProcess.EventIsProcessEvent(event): + state = lldb.SBProcess.GetStateFromEvent(event) + if state == lldb.eStateInvalid: + # Not a state event + print 'process event = %s' % (event) + else: + print "process state changed event: %s" % (lldb.SBDebugger.StateAsCString(state)) + if state == lldb.eStateStopped: + if stop_idx == 0: + if launch_info: + print "process %u launched" % (pid) + run_commands( + command_interpreter, ['breakpoint list']) + else: + print "attached to process %u" % (pid) + for m in target.modules: + print m + if options.breakpoints: + for bp in options.breakpoints: + debugger.HandleCommand( + "_regexp-break %s" % (bp)) + run_commands( + command_interpreter, ['breakpoint list']) + run_commands( + command_interpreter, options.launch_commands) + else: + if options.verbose: + print "process %u stopped" % (pid) + run_commands( + command_interpreter, options.stop_commands) + stop_idx += 1 + print_threads(process, options) + print "continuing process %u" % (pid) + process.Continue() + elif state == lldb.eStateExited: + exit_desc = process.GetExitDescription() + if exit_desc: + print "process %u exited with status %u: %s" % (pid, process.GetExitStatus(), exit_desc) + else: + print "process %u exited with status %u" % (pid, process.GetExitStatus()) + run_commands( + command_interpreter, options.exit_commands) + done = True + elif state == lldb.eStateCrashed: + print "process %u crashed" % (pid) + print_threads(process, options) + run_commands( + command_interpreter, options.crash_commands) + done = True + elif state == lldb.eStateDetached: + print "process %u detached" % (pid) + done = True + elif state == lldb.eStateRunning: + # process is running, don't say anything, + # we will always get one of these after + # resuming + if options.verbose: + print "process %u resumed" % (pid) + elif state == lldb.eStateUnloaded: + print "process %u unloaded, this shouldn't happen" % (pid) + done = True + elif state == lldb.eStateConnected: + print "process connected" + elif state == lldb.eStateAttaching: + print "process attaching" + elif state == lldb.eStateLaunching: + print "process launching" + else: + print 'event = %s' % (event) + else: + # timeout waiting for an event + print "no process event for %u seconds, killing the process..." % (options.event_timeout) + done = True + # Now that we are done dump the stdout and stderr + process_stdout = process.GetSTDOUT(1024) + if process_stdout: + print "Process STDOUT:\n%s" % (process_stdout) + while process_stdout: + process_stdout = process.GetSTDOUT(1024) + print process_stdout + process_stderr = process.GetSTDERR(1024) + if process_stderr: + print "Process STDERR:\n%s" % (process_stderr) + while process_stderr: + process_stderr = process.GetSTDERR(1024) + print process_stderr + process.Kill() # kill the process + else: + if error: + print error + else: + if launch_info: + print 'error: launch failed' + else: + print 'error: attach failed' + + lldb.SBDebugger.Terminate() + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/examples/python/pytracer.py b/examples/python/pytracer.py new file mode 100644 index 000000000..a166f21e9 --- /dev/null +++ b/examples/python/pytracer.py @@ -0,0 +1,360 @@ +import sys +import inspect +from collections import OrderedDict + + +class TracebackFancy: + + def __init__(self, traceback): + self.t = traceback + + def getFrame(self): + return FrameFancy(self.t.tb_frame) + + def getLineNumber(self): + return self.t.tb_lineno if self.t is not None else None + + def getNext(self): + return TracebackFancy(self.t.tb_next) + + def __str__(self): + if self.t is None: + return "" + str_self = "%s @ %s" % ( + self.getFrame().getName(), self.getLineNumber()) + return str_self + "\n" + self.getNext().__str__() + + +class ExceptionFancy: + + def __init__(self, frame): + self.etraceback = frame.f_exc_traceback + self.etype = frame.exc_type + self.evalue = frame.f_exc_value + + def __init__(self, tb, ty, va): + self.etraceback = tb + self.etype = ty + self.evalue = va + + def getTraceback(self): + return TracebackFancy(self.etraceback) + + def __nonzero__(self): + return self.etraceback is not None or self.etype is not None or self.evalue is not None + + def getType(self): + return str(self.etype) + + def getValue(self): + return self.evalue + + +class CodeFancy: + + def __init__(self, code): + self.c = code + + def getArgCount(self): + return self.c.co_argcount if self.c is not None else 0 + + def getFilename(self): + return self.c.co_filename if self.c is not None else "" + + def getVariables(self): + return self.c.co_varnames if self.c is not None else [] + + def getName(self): + return self.c.co_name if self.c is not None else "" + + def getFileName(self): + return self.c.co_filename if self.c is not None else "" + + +class ArgsFancy: + + def __init__(self, frame, arginfo): + self.f = frame + self.a = arginfo + + def __str__(self): + args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs() + ret = "" + count = 0 + size = len(args) + for arg in args: + ret = ret + ("%s = %s" % (arg, args[arg])) + count = count + 1 + if count < size: + ret = ret + ", " + if varargs: + if size > 0: + ret = ret + " " + ret = ret + "varargs are " + str(varargs) + if kwargs: + if size > 0: + ret = ret + " " + ret = ret + "kwargs are " + str(kwargs) + return ret + + def getNumArgs(wantVarargs=False, wantKWArgs=False): + args, varargs, keywords, values = self.a + size = len(args) + if varargs and wantVarargs: + size = size + len(self.getVarArgs()) + if keywords and wantKWArgs: + size = size + len(self.getKWArgs()) + return size + + def getArgs(self): + args, _, _, values = self.a + argWValues = OrderedDict() + for arg in args: + argWValues[arg] = values[arg] + return argWValues + + def getVarArgs(self): + _, vargs, _, _ = self.a + if vargs: + return self.f.f_locals[vargs] + return () + + def getKWArgs(self): + _, _, kwargs, _ = self.a + if kwargs: + return self.f.f_locals[kwargs] + return {} + + +class FrameFancy: + + def __init__(self, frame): + self.f = frame + + def getCaller(self): + return FrameFancy(self.f.f_back) + + def getLineNumber(self): + return self.f.f_lineno if self.f is not None else 0 + + def getCodeInformation(self): + return CodeFancy(self.f.f_code) if self.f is not None else None + + def getExceptionInfo(self): + return ExceptionFancy(self.f) if self.f is not None else None + + def getName(self): + return self.getCodeInformation().getName() if self.f is not None else "" + + def getFileName(self): + return self.getCodeInformation().getFileName() if self.f is not None else "" + + def getLocals(self): + return self.f.f_locals if self.f is not None else {} + + def getArgumentInfo(self): + return ArgsFancy( + self.f, inspect.getargvalues( + self.f)) if self.f is not None else None + + +class TracerClass: + + def callEvent(self, frame): + pass + + def lineEvent(self, frame): + pass + + def returnEvent(self, frame, retval): + pass + + def exceptionEvent(self, frame, exception, value, traceback): + pass + + def cCallEvent(self, frame, cfunct): + pass + + def cReturnEvent(self, frame, cfunct): + pass + + def cExceptionEvent(self, frame, cfunct): + pass + +tracer_impl = TracerClass() + + +def the_tracer_entrypoint(frame, event, args): + if tracer_impl is None: + return None + if event == "call": + call_retval = tracer_impl.callEvent(FrameFancy(frame)) + if not call_retval: + return None + return the_tracer_entrypoint + elif event == "line": + line_retval = tracer_impl.lineEvent(FrameFancy(frame)) + if not line_retval: + return None + return the_tracer_entrypoint + elif event == "return": + tracer_impl.returnEvent(FrameFancy(frame), args) + elif event == "exception": + exty, exva, extb = args + exception_retval = tracer_impl.exceptionEvent( + FrameFancy(frame), ExceptionFancy(extb, exty, exva)) + if not exception_retval: + return None + return the_tracer_entrypoint + elif event == "c_call": + tracer_impl.cCallEvent(FrameFancy(frame), args) + elif event == "c_return": + tracer_impl.cReturnEvent(FrameFancy(frame), args) + elif event == "c_exception": + tracer_impl.cExceptionEvent(FrameFancy(frame), args) + return None + + +def enable(t=None): + global tracer_impl + if t: + tracer_impl = t + sys.settrace(the_tracer_entrypoint) + + +def disable(): + sys.settrace(None) + + +class LoggingTracer: + + def callEvent(self, frame): + print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()) + + def lineEvent(self, frame): + print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName() + + def returnEvent(self, frame, retval): + print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals()) + + def exceptionEvent(self, frame, exception): + print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()) + print "tb: " + str(exception.getTraceback()) + +# the same functionality as LoggingTracer, but with a little more +# lldb-specific smarts + + +class LLDBAwareTracer: + + def callEvent(self, frame): + if frame.getName() == "": + return + if frame.getName() == "run_one_line": + print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"]) + return + if "Python.framework" in frame.getFileName(): + print "call into Python at " + frame.getName() + return + if frame.getName() == "__init__" and frame.getCaller().getName( + ) == "run_one_line" and frame.getCaller().getLineNumber() == 101: + return False + strout = "call " + frame.getName() + if (frame.getCaller().getFileName() == ""): + strout += " from LLDB - args are " + args = frame.getArgumentInfo().getArgs() + for arg in args: + if arg == "dict" or arg == "internal_dict": + continue + strout = strout + ("%s = %s " % (arg, args[arg])) + else: + strout += " from " + frame.getCaller().getName() + " @ " + \ + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo()) + print strout + + def lineEvent(self, frame): + if frame.getName() == "": + return + if frame.getName() == "run_one_line": + print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"], frame.getLineNumber()) + return + if "Python.framework" in frame.getFileName(): + print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber()) + return + strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + \ + " locals are " + if (frame.getCaller().getFileName() == ""): + locals = frame.getLocals() + for local in locals: + if local == "dict" or local == "internal_dict": + continue + strout = strout + ("%s = %s " % (local, locals[local])) + else: + strout = strout + str(frame.getLocals()) + strout = strout + " in " + frame.getFileName() + print strout + + def returnEvent(self, frame, retval): + if frame.getName() == "": + return + if frame.getName() == "run_one_line": + print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"], retval) + return + if "Python.framework" in frame.getFileName(): + print "return from Python at " + frame.getName() + " return value is " + str(retval) + return + strout = "return from " + frame.getName() + " return value is " + \ + str(retval) + " locals are " + if (frame.getCaller().getFileName() == ""): + locals = frame.getLocals() + for local in locals: + if local == "dict" or local == "internal_dict": + continue + strout = strout + ("%s = %s " % (local, locals[local])) + else: + strout = strout + str(frame.getLocals()) + strout = strout + " in " + frame.getFileName() + print strout + + def exceptionEvent(self, frame, exception): + if frame.getName() == "": + return + print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()) + print "tb: " + str(exception.getTraceback()) + + +def f(x, y=None): + if x > 0: + return 2 + f(x - 2) + return 35 + + +def g(x): + return 1.134 / x + + +def print_keyword_args(**kwargs): + # kwargs is a dict of the keyword args passed to the function + for key, value in kwargs.iteritems(): + print "%s = %s" % (key, value) + + +def total(initial=5, *numbers, **keywords): + count = initial + for number in numbers: + count += number + for key in keywords: + count += keywords[key] + return count + +if __name__ == "__main__": + enable(LoggingTracer()) + f(5) + f(5, 1) + print_keyword_args(first_name="John", last_name="Doe") + total(10, 1, 2, 3, vegetables=50, fruits=100) + try: + g(0) + except: + pass + disable() diff --git a/examples/python/sbvalue.py b/examples/python/sbvalue.py new file mode 100755 index 000000000..6e512998d --- /dev/null +++ b/examples/python/sbvalue.py @@ -0,0 +1,268 @@ +#!/usr/bin/python + +import lldb + + +class value(object): + '''A class that wraps an lldb.SBValue object and returns an object that + can be used as an object with attribytes:\n + argv = a.value(lldb.frame.FindVariable('argv'))\n + argv.name - return the name of the value that this object contains\n + argv.type - return the lldb.SBType for this value + argv.type_name - return the name of the type + argv.size - return the byte size of this value + argv.is_in_scope - return true if this value is currently in scope + argv.is_pointer - return true if this value is a pointer + argv.format - return the current format for this value + argv.value - return the value's value as a string + argv.summary - return a summary of this value's value + argv.description - return the runtime description for this value + argv.location - return a string that represents the values location (address, register, etc) + argv.target - return the lldb.SBTarget for this value + argv.process - return the lldb.SBProcess for this value + argv.thread - return the lldb.SBThread for this value + argv.frame - return the lldb.SBFrame for this value + argv.num_children - return the number of children this value has + argv.children - return a list of sbvalue objects that represents all of the children of this value + ''' + + def __init__(self, sbvalue): + self.sbvalue = sbvalue + + def __nonzero__(self): + return self.sbvalue.__nonzero__() + + def __repr__(self): + return self.sbvalue.__repr__() + + def __str__(self): + return self.sbvalue.__str__() + + def __getitem__(self, key): + if isinstance(key, int): + return value( + self.sbvalue.GetChildAtIndex( + key, lldb.eNoDynamicValues, True)) + raise TypeError + + def __getattr__(self, name): + if name == 'name': + return self.sbvalue.GetName() + if name == 'type': + return self.sbvalue.GetType() + if name == 'type_name': + return self.sbvalue.GetTypeName() + if name == 'size': + return self.sbvalue.GetByteSize() + if name == 'is_in_scope': + return self.sbvalue.IsInScope() + if name == 'is_pointer': + return self.sbvalue.TypeIsPointerType() + if name == 'format': + return self.sbvalue.GetFormat() + if name == 'value': + return self.sbvalue.GetValue() + if name == 'summary': + return self.sbvalue.GetSummary() + if name == 'description': + return self.sbvalue.GetObjectDescription() + if name == 'location': + return self.sbvalue.GetLocation() + if name == 'target': + return self.sbvalue.GetTarget() + if name == 'process': + return self.sbvalue.GetProcess() + if name == 'thread': + return self.sbvalue.GetThread() + if name == 'frame': + return self.sbvalue.GetFrame() + if name == 'num_children': + return self.sbvalue.GetNumChildren() + if name == 'children': + # Returns an array of sbvalue objects, one for each child of + # the value for the lldb.SBValue + children = [] + for i in range(self.sbvalue.GetNumChildren()): + children.append( + value( + self.sbvalue.GetChildAtIndex( + i, + lldb.eNoDynamicValues, + True))) + return children + raise AttributeError + + +class variable(object): + '''A class that treats a lldb.SBValue and allows it to be used just as + a variable would be in code. So if you have a Point structure variable + in your code, you would be able to do: "pt.x + pt.y"''' + + def __init__(self, sbvalue): + self.sbvalue = sbvalue + + def __nonzero__(self): + return self.sbvalue.__nonzero__() + + def __repr__(self): + return self.sbvalue.__repr__() + + def __str__(self): + return self.sbvalue.__str__() + + def __getitem__(self, key): + # Allow array access if this value has children... + if isinstance(key, int): + return variable( + self.sbvalue.GetValueForExpressionPath( + "[%i]" % + key)) + raise TypeError + + def __getattr__(self, name): + child_sbvalue = self.sbvalue.GetChildMemberWithName(name) + if child_sbvalue: + return variable(child_sbvalue) + raise AttributeError + + def __add__(self, other): + return int(self) + int(other) + + def __sub__(self, other): + return int(self) - int(other) + + def __mul__(self, other): + return int(self) * int(other) + + def __floordiv__(self, other): + return int(self) // int(other) + + def __mod__(self, other): + return int(self) % int(other) + + def __divmod__(self, other): + return int(self) % int(other) + + def __pow__(self, other): + return int(self) ** int(other) + + def __lshift__(self, other): + return int(self) << int(other) + + def __rshift__(self, other): + return int(self) >> int(other) + + def __and__(self, other): + return int(self) & int(other) + + def __xor__(self, other): + return int(self) ^ int(other) + + def __or__(self, other): + return int(self) | int(other) + + def __div__(self, other): + return int(self) / int(other) + + def __truediv__(self, other): + return int(self) / int(other) + + def __iadd__(self, other): + result = self.__add__(other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __isub__(self, other): + result = self.__sub__(other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __imul__(self, other): + result = self.__mul__(other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __idiv__(self, other): + result = self.__div__(other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __itruediv__(self, other): + result = self.__truediv__(other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __ifloordiv__(self, other): + result = self.__floordiv__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __imod__(self, other): + result = self.__and__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __ipow__(self, other): + result = self.__pow__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __ipow__(self, other, modulo): + result = self.__pow__(self, other, modulo) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __ilshift__(self, other): + result = self.__lshift__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __irshift__(self, other): + result = self.__rshift__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __iand__(self, other): + result = self.__and__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __ixor__(self, other): + result = self.__xor__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __ior__(self, other): + result = self.__ior__(self, other) + self.sbvalue.SetValueFromCString(str(result)) + return result + + def __neg__(self): + return -int(self) + + def __pos__(self): + return +int(self) + + def __abs__(self): + return abs(int(self)) + + def __invert__(self): + return ~int(self) + + def __complex__(self): + return complex(int(self)) + + def __int__(self): + return self.sbvalue.GetValueAsSigned() + + def __long__(self): + return self.sbvalue.GetValueAsSigned() + + def __float__(self): + return float(self.sbvalue.GetValueAsSigned()) + + def __oct__(self): + return '0%o' % self.sbvalue.GetValueAsSigned() + + def __hex__(self): + return '0x%x' % self.sbvalue.GetValueAsSigned() diff --git a/examples/python/scripted_step.py b/examples/python/scripted_step.py new file mode 100644 index 000000000..453b5e229 --- /dev/null +++ b/examples/python/scripted_step.py @@ -0,0 +1,244 @@ +############################################################################# +# This script contains two trivial examples of simple "scripted step" classes. +# To fully understand how the lldb "Thread Plan" architecture works, read the +# comments at the beginning of ThreadPlan.h in the lldb sources. The python +# interface is a reduced version of the full internal mechanism, but captures +# most of the power with a much simpler interface. +# +# But I'll attempt a brief summary here. +# Stepping in lldb is done independently for each thread. Moreover, the stepping +# operations are stackable. So for instance if you did a "step over", and in +# the course of stepping over you hit a breakpoint, stopped and stepped again, +# the first "step-over" would be suspended, and the new step operation would +# be enqueued. Then if that step over caused the program to hit another breakpoint, +# lldb would again suspend the second step and return control to the user, so +# now there are two pending step overs. Etc. with all the other stepping +# operations. Then if you hit "continue" the bottom-most step-over would complete, +# and another continue would complete the first "step-over". +# +# lldb represents this system with a stack of "Thread Plans". Each time a new +# stepping operation is requested, a new plan is pushed on the stack. When the +# operation completes, it is pushed off the stack. +# +# The bottom-most plan in the stack is the immediate controller of stepping, +# most importantly, when the process resumes, the bottom most plan will get +# asked whether to set the program running freely, or to instruction-single-step +# the current thread. In the scripted interface, you indicate this by returning +# False or True respectively from the should_step method. +# +# Each time the process stops the thread plan stack for each thread that stopped +# "for a reason", Ii.e. a single-step completed on that thread, or a breakpoint +# was hit), is queried to determine how to proceed, starting from the most +# recently pushed plan, in two stages: +# +# 1) Each plan is asked if it "explains" the stop. The first plan to claim the +# stop wins. In scripted Thread Plans, this is done by returning True from +# the "explains_stop method. This is how, for instance, control is returned +# to the User when the "step-over" plan hits a breakpoint. The step-over +# plan doesn't explain the breakpoint stop, so it returns false, and the +# breakpoint hit is propagated up the stack to the "base" thread plan, which +# is the one that handles random breakpoint hits. +# +# 2) Then the plan that won the first round is asked if the process should stop. +# This is done in the "should_stop" method. The scripted plans actually do +# three jobs in should_stop: +# a) They determine if they have completed their job or not. If they have +# they indicate that by calling SetPlanComplete on their thread plan. +# b) They decide whether they want to return control to the user or not. +# They do this by returning True or False respectively. +# c) If they are not done, they set up whatever machinery they will use +# the next time the thread continues. +# +# Note that deciding to return control to the user, and deciding your plan +# is done, are orthgonal operations. You could set up the next phase of +# stepping, and then return True from should_stop, and when the user next +# "continued" the process your plan would resume control. Of course, the +# user might also "step-over" or some other operation that would push a +# different plan, which would take control till it was done. +# +# One other detail you should be aware of, if the plan below you on the +# stack was done, then it will be popped and the next plan will take control +# and its "should_stop" will be called. +# +# Note also, there should be another method called when your plan is popped, +# to allow you to do whatever cleanup is required. I haven't gotten to that +# yet. For now you should do that at the same time you mark your plan complete. +# +# 3) After the round of negotiation over whether to stop or not is done, all the +# plans get asked if they are "stale". If they are say they are stale +# then they will get popped. This question is asked with the "is_stale" method. +# +# This is useful, for instance, in the FinishPrintAndContinue plan. What might +# happen here is that after continuing but before the finish is done, the program +# could hit another breakpoint and stop. Then the user could use the step +# command repeatedly until they leave the frame of interest by stepping. +# In that case, the step plan is the one that will be responsible for stopping, +# and the finish plan won't be asked should_stop, it will just be asked if it +# is stale. In this case, if the step_out plan that the FinishPrintAndContinue +# plan is driving is stale, so is ours, and it is time to do our printing. +# +# Both examples show stepping through an address range for 20 bytes from the +# current PC. The first one does it by single stepping and checking a condition. +# It doesn't, however handle the case where you step into another frame while +# still in the current range in the starting frame. +# +# That is better handled in the second example by using the built-in StepOverRange +# thread plan. +# +# To use these stepping modes, you would do: +# +# (lldb) command script import scripted_step.py +# (lldb) thread step-scripted -C scripted_step.SimpleStep +# or +# +# (lldb) thread step-scripted -C scripted_step.StepWithPlan + +import lldb + + +class SimpleStep: + + def __init__(self, thread_plan, dict): + self.thread_plan = thread_plan + self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPC() + + def explains_stop(self, event): + # We are stepping, so if we stop for any other reason, it isn't + # because of us. + if self.thread_plan.GetThread().GetStopReason() == lldb.eStopReasonTrace: + return True + else: + return False + + def should_stop(self, event): + cur_pc = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPC() + + if cur_pc < self.start_address or cur_pc >= self.start_address + 20: + self.thread_plan.SetPlanComplete(True) + return True + else: + return False + + def should_step(self): + return True + + +class StepWithPlan: + + def __init__(self, thread_plan, dict): + self.thread_plan = thread_plan + self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPCAddress() + self.step_thread_plan = thread_plan.QueueThreadPlanForStepOverRange( + self.start_address, 20) + + def explains_stop(self, event): + # Since all I'm doing is running a plan, I will only ever get askedthis + # if myplan doesn't explain the stop, and in that caseI don'teither. + return False + + def should_stop(self, event): + if self.step_thread_plan.IsPlanComplete(): + self.thread_plan.SetPlanComplete(True) + return True + else: + return False + + def should_step(self): + return False + +# Here's another example which does "step over" through the current function, +# and when it stops at each line, it checks some condition (in this example the +# value of a variable) and stops if that condition is true. + + +class StepCheckingCondition: + + def __init__(self, thread_plan, dict): + self.thread_plan = thread_plan + self.start_frame = thread_plan.GetThread().GetFrameAtIndex(0) + self.queue_next_plan() + + def queue_next_plan(self): + cur_frame = self.thread_plan.GetThread().GetFrameAtIndex(0) + cur_line_entry = cur_frame.GetLineEntry() + start_address = cur_line_entry.GetStartAddress() + end_address = cur_line_entry.GetEndAddress() + line_range = end_address.GetFileAddress() - start_address.GetFileAddress() + self.step_thread_plan = self.thread_plan.QueueThreadPlanForStepOverRange( + start_address, line_range) + + def explains_stop(self, event): + # We are stepping, so if we stop for any other reason, it isn't + # because of us. + return False + + def should_stop(self, event): + if not self.step_thread_plan.IsPlanComplete(): + return False + + frame = self.thread_plan.GetThread().GetFrameAtIndex(0) + if not self.start_frame.IsEqual(frame): + self.thread_plan.SetPlanComplete(True) + return True + + # This part checks the condition. In this case we are expecting + # some integer variable called "a", and will stop when it is 20. + a_var = frame.FindVariable("a") + + if not a_var.IsValid(): + print "A was not valid." + return True + + error = lldb.SBError() + a_value = a_var.GetValueAsSigned(error) + if not error.Success(): + print "A value was not good." + return True + + if a_value == 20: + self.thread_plan.SetPlanComplete(True) + return True + else: + self.queue_next_plan() + return False + + def should_step(self): + return True + +# Here's an example that steps out of the current frame, gathers some information +# and then continues. The information in this case is rax. Currently the thread +# plans are not a safe place to call lldb command-line commands, so the information +# is gathered through SB API calls. + + +class FinishPrintAndContinue: + + def __init__(self, thread_plan, dict): + self.thread_plan = thread_plan + self.step_out_thread_plan = thread_plan.QueueThreadPlanForStepOut( + 0, True) + self.thread = self.thread_plan.GetThread() + + def is_stale(self): + if self.step_out_thread_plan.IsPlanStale(): + self.do_print() + return True + else: + return False + + def explains_stop(self, event): + return False + + def should_stop(self, event): + if self.step_out_thread_plan.IsPlanComplete(): + self.do_print() + self.thread_plan.SetPlanComplete(True) + return False + + def do_print(self): + frame_0 = self.thread.frames[0] + rax_value = frame_0.FindRegister("rax") + if rax_value.GetError().Success(): + print "RAX on exit: ", rax_value.GetValue() + else: + print "Couldn't get rax value:", rax_value.GetError().GetCString() diff --git a/examples/python/shadow.py b/examples/python/shadow.py new file mode 100644 index 000000000..0556cfc55 --- /dev/null +++ b/examples/python/shadow.py @@ -0,0 +1,58 @@ +#!/usr/bin/python + +import lldb +import shlex + + +@lldb.command("shadow") +def check_shadow_command(debugger, command, exe_ctx, result, dict): + '''Check the currently selected stack frame for shadowed variables''' + process = exe_ctx.GetProcess() + state = process.GetState() + if state != lldb.eStateStopped: + print >>result, "process must be stopped, state is %s" % lldb.SBDebugger.StateAsCString( + state) + return + frame = exe_ctx.GetFrame() + if not frame: + print >>result, "invalid frame" + return + # Parse command line args + command_args = shlex.split(command) + # TODO: add support for using arguments that are passed to this command... + + # Make a dictionary of variable name to "SBBlock and SBValue" + shadow_dict = {} + + num_shadowed_variables = 0 + # Get the deepest most block from the current frame + block = frame.GetBlock() + # Iterate through the block and all of its parents + while block.IsValid(): + # Get block variables from the current block only + block_vars = block.GetVariables(frame, True, True, True, 0) + # Iterate through all variables in the current block + for block_var in block_vars: + # Since we can have multiple shadowed variables, we our variable + # name dictionary to have an array or "block + variable" pairs so + # We can correctly print out all shadowed variables and whow which + # blocks they come from + block_var_name = block_var.GetName() + if block_var_name in shadow_dict: + shadow_dict[block_var_name].append(block_var) + else: + shadow_dict[block_var_name] = [block_var] + # Get the parent block and continue + block = block.GetParent() + + num_shadowed_variables = 0 + if shadow_dict: + for name in shadow_dict.keys(): + shadow_vars = shadow_dict[name] + if len(shadow_vars) > 1: + print '"%s" is shadowed by the following declarations:' % (name) + num_shadowed_variables += 1 + for shadow_var in shadow_vars: + print >>result, str(shadow_var.GetDeclaration()) + if num_shadowed_variables == 0: + print >>result, 'no variables are shadowed' diff --git a/examples/python/sources.py b/examples/python/sources.py new file mode 100644 index 000000000..b912f43f7 --- /dev/null +++ b/examples/python/sources.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import lldb +import shlex + + +def dump_module_sources(module, result): + if module: + print >> result, "Module: %s" % (module.file) + for compile_unit in module.compile_units: + if compile_unit.file: + print >> result, " %s" % (compile_unit.file) + + +def info_sources(debugger, command, result, dict): + description = '''This command will dump all compile units in any modules that are listed as arguments, or for all modules if no arguments are supplied.''' + module_names = shlex.split(command) + target = debugger.GetSelectedTarget() + if module_names: + for module_name in module_names: + dump_module_sources(target.module[module_name], result) + else: + for module in target.modules: + dump_module_sources(module, result) + + +def __lldb_init_module(debugger, dict): + # Add any commands contained in this module to LLDB + debugger.HandleCommand( + 'command script add -f sources.info_sources info_sources') + print 'The "info_sources" command has been installed, type "help info_sources" or "info_sources --help" for detailed help.' diff --git a/examples/python/stacks.py b/examples/python/stacks.py new file mode 100755 index 000000000..fec879993 --- /dev/null +++ b/examples/python/stacks.py @@ -0,0 +1,69 @@ +#!/usr/bin/python + +import lldb +import commands +import optparse +import shlex + + +def stack_frames(debugger, command, result, dict): + command_args = shlex.split(command) + usage = "usage: %prog [options] [PATH ...]" + description = '''This command will enumerate all stack frames, print the stack size for each, and print an aggregation of which functions have the largest stack frame sizes at the end.''' + parser = optparse.OptionParser( + description=description, prog='ls', usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + try: + (options, args) = parser.parse_args(command_args) + except: + return + + target = debugger.GetSelectedTarget() + process = target.GetProcess() + + frame_info = {} + for thread in process: + last_frame = None + print "thread %u" % (thread.id) + for frame in thread.frames: + if last_frame: + frame_size = 0 + if frame.idx == 1: + if frame.fp == last_frame.fp: + # No frame one the first frame (might be right at the + # entry point) + first_frame_size = 0 + frame_size = frame.fp - frame.sp + else: + # First frame that has a valid size + first_frame_size = last_frame.fp - last_frame.sp + print "<%#7x> %s" % (first_frame_size, last_frame) + if first_frame_size: + name = last_frame.name + if name not in frame_info: + frame_info[name] = first_frame_size + else: + frame_info[name] += first_frame_size + else: + # Second or higher frame + frame_size = frame.fp - last_frame.fp + print "<%#7x> %s" % (frame_size, frame) + if frame_size > 0: + name = frame.name + if name not in frame_info: + frame_info[name] = frame_size + else: + frame_info[name] += frame_size + last_frame = frame + print frame_info + + +lldb.debugger.HandleCommand( + "command script add -f stacks.stack_frames stack_frames") +print "A new command called 'stack_frames' was added, type 'stack_frames --help' for more information." diff --git a/examples/python/symbolication.py b/examples/python/symbolication.py new file mode 100755 index 000000000..b655ad0d1 --- /dev/null +++ b/examples/python/symbolication.py @@ -0,0 +1,727 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# +# To use this in the embedded python interpreter using "lldb": +# +# cd /path/containing/crashlog.py +# lldb +# (lldb) script import crashlog +# "crashlog" command installed, type "crashlog --help" for detailed help +# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash +# +# The benefit of running the crashlog command inside lldb in the +# embedded python interpreter is when the command completes, there +# will be a target with all of the files loaded at the locations +# described in the crash log. Only the files that have stack frames +# in the backtrace will be loaded unless the "--load-all" option +# has been specified. This allows users to explore the program in the +# state it was in right at crash time. +# +# On MacOSX csh, tcsh: +# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) +# +# On MacOSX sh, bash: +# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash +#---------------------------------------------------------------------- + +import lldb +import commands +import optparse +import os +import plistlib +import re +import shlex +import sys +import time +import uuid + + +class Address: + """Class that represents an address that will be symbolicated""" + + def __init__(self, target, load_addr): + self.target = target + self.load_addr = load_addr # The load address that this object represents + # the resolved lldb.SBAddress (if any), named so_addr for + # section/offset address + self.so_addr = None + self.sym_ctx = None # The cached symbol context for this address + # Any original textual description of this address to be used as a + # backup in case symbolication fails + self.description = None + self.symbolication = None # The cached symbolicated string that describes this address + self.inlined = False + + def __str__(self): + s = "%#16.16x" % (self.load_addr) + if self.symbolication: + s += " %s" % (self.symbolication) + elif self.description: + s += " %s" % (self.description) + elif self.so_addr: + s += " %s" % (self.so_addr) + return s + + def resolve_addr(self): + if self.so_addr is None: + self.so_addr = self.target.ResolveLoadAddress(self.load_addr) + return self.so_addr + + def is_inlined(self): + return self.inlined + + def get_symbol_context(self): + if self.sym_ctx is None: + sb_addr = self.resolve_addr() + if sb_addr: + self.sym_ctx = self.target.ResolveSymbolContextForAddress( + sb_addr, lldb.eSymbolContextEverything) + else: + self.sym_ctx = lldb.SBSymbolContext() + return self.sym_ctx + + def get_instructions(self): + sym_ctx = self.get_symbol_context() + if sym_ctx: + function = sym_ctx.GetFunction() + if function: + return function.GetInstructions(self.target) + return sym_ctx.GetSymbol().GetInstructions(self.target) + return None + + def symbolicate(self, verbose=False): + if self.symbolication is None: + self.symbolication = '' + self.inlined = False + sym_ctx = self.get_symbol_context() + if sym_ctx: + module = sym_ctx.GetModule() + if module: + # Print full source file path in verbose mode + if verbose: + self.symbolication += str(module.GetFileSpec()) + '`' + else: + self.symbolication += module.GetFileSpec().GetFilename() + '`' + function_start_load_addr = -1 + function = sym_ctx.GetFunction() + block = sym_ctx.GetBlock() + line_entry = sym_ctx.GetLineEntry() + symbol = sym_ctx.GetSymbol() + inlined_block = block.GetContainingInlinedBlock() + if function: + self.symbolication += function.GetName() + + if inlined_block: + self.inlined = True + self.symbolication += ' [inlined] ' + \ + inlined_block.GetInlinedName() + block_range_idx = inlined_block.GetRangeIndexForBlockAddress( + self.so_addr) + if block_range_idx < lldb.UINT32_MAX: + block_range_start_addr = inlined_block.GetRangeStartAddress( + block_range_idx) + function_start_load_addr = block_range_start_addr.GetLoadAddress( + self.target) + if function_start_load_addr == -1: + function_start_load_addr = function.GetStartAddress().GetLoadAddress(self.target) + elif symbol: + self.symbolication += symbol.GetName() + function_start_load_addr = symbol.GetStartAddress().GetLoadAddress(self.target) + else: + self.symbolication = '' + return False + + # Dump the offset from the current function or symbol if it + # is non zero + function_offset = self.load_addr - function_start_load_addr + if function_offset > 0: + self.symbolication += " + %u" % (function_offset) + elif function_offset < 0: + self.symbolication += " %i (invalid negative offset, file a bug) " % function_offset + + # Print out any line information if any is available + if line_entry.GetFileSpec(): + # Print full source file path in verbose mode + if verbose: + self.symbolication += ' at %s' % line_entry.GetFileSpec() + else: + self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename() + self.symbolication += ':%u' % line_entry.GetLine() + column = line_entry.GetColumn() + if column > 0: + self.symbolication += ':%u' % column + return True + return False + + +class Section: + """Class that represents an load address range""" + sect_info_regex = re.compile('(?P[^=]+)=(?P.*)') + addr_regex = re.compile('^\s*(?P0x[0-9A-Fa-f]+)\s*$') + range_regex = re.compile( + '^\s*(?P0x[0-9A-Fa-f]+)\s*(?P[-+])\s*(?P0x[0-9A-Fa-f]+)\s*$') + + def __init__(self, start_addr=None, end_addr=None, name=None): + self.start_addr = start_addr + self.end_addr = end_addr + self.name = name + + @classmethod + def InitWithSBTargetAndSBSection(cls, target, section): + sect_load_addr = section.GetLoadAddress(target) + if sect_load_addr != lldb.LLDB_INVALID_ADDRESS: + obj = cls( + sect_load_addr, + sect_load_addr + + section.size, + section.name) + return obj + else: + return None + + def contains(self, addr): + return self.start_addr <= addr and addr < self.end_addr + + def set_from_string(self, s): + match = self.sect_info_regex.match(s) + if match: + self.name = match.group('name') + range_str = match.group('range') + addr_match = self.addr_regex.match(range_str) + if addr_match: + self.start_addr = int(addr_match.group('start'), 16) + self.end_addr = None + return True + + range_match = self.range_regex.match(range_str) + if range_match: + self.start_addr = int(range_match.group('start'), 16) + self.end_addr = int(range_match.group('end'), 16) + op = range_match.group('op') + if op == '+': + self.end_addr += self.start_addr + return True + print 'error: invalid section info string "%s"' % s + print 'Valid section info formats are:' + print 'Format Example Description' + print '--------------------- -----------------------------------------------' + print '= __TEXT=0x123000 Section from base address only' + print '=- __TEXT=0x123000-0x124000 Section from base address and end address' + print '=+ __TEXT=0x123000+0x1000 Section from base address and size' + return False + + def __str__(self): + if self.name: + if self.end_addr is not None: + if self.start_addr is not None: + return "%s=[0x%16.16x - 0x%16.16x)" % ( + self.name, self.start_addr, self.end_addr) + else: + if self.start_addr is not None: + return "%s=0x%16.16x" % (self.name, self.start_addr) + return self.name + return "" + + +class Image: + """A class that represents an executable image and any associated data""" + + def __init__(self, path, uuid=None): + self.path = path + self.resolved_path = None + self.resolved = False + self.unavailable = False + self.uuid = uuid + self.section_infos = list() + self.identifier = None + self.version = None + self.arch = None + self.module = None + self.symfile = None + self.slide = None + + @classmethod + def InitWithSBTargetAndSBModule(cls, target, module): + '''Initialize this Image object with a module from a target.''' + obj = cls(module.file.fullpath, module.uuid) + obj.resolved_path = module.platform_file.fullpath + obj.resolved = True + obj.arch = module.triple + for section in module.sections: + symb_section = Section.InitWithSBTargetAndSBSection( + target, section) + if symb_section: + obj.section_infos.append(symb_section) + obj.arch = module.triple + obj.module = module + obj.symfile = None + obj.slide = None + return obj + + def dump(self, prefix): + print "%s%s" % (prefix, self) + + def debug_dump(self): + print 'path = "%s"' % (self.path) + print 'resolved_path = "%s"' % (self.resolved_path) + print 'resolved = %i' % (self.resolved) + print 'unavailable = %i' % (self.unavailable) + print 'uuid = %s' % (self.uuid) + print 'section_infos = %s' % (self.section_infos) + print 'identifier = "%s"' % (self.identifier) + print 'version = %s' % (self.version) + print 'arch = %s' % (self.arch) + print 'module = %s' % (self.module) + print 'symfile = "%s"' % (self.symfile) + print 'slide = %i (0x%x)' % (self.slide, self.slide) + + def __str__(self): + s = '' + if self.uuid: + s += "%s " % (self.get_uuid()) + if self.arch: + s += "%s " % (self.arch) + if self.version: + s += "%s " % (self.version) + resolved_path = self.get_resolved_path() + if resolved_path: + s += "%s " % (resolved_path) + for section_info in self.section_infos: + s += ", %s" % (section_info) + if self.slide is not None: + s += ', slide = 0x%16.16x' % self.slide + return s + + def add_section(self, section): + # print "added '%s' to '%s'" % (section, self.path) + self.section_infos.append(section) + + def get_section_containing_load_addr(self, load_addr): + for section_info in self.section_infos: + if section_info.contains(load_addr): + return section_info + return None + + def get_resolved_path(self): + if self.resolved_path: + return self.resolved_path + elif self.path: + return self.path + return None + + def get_resolved_path_basename(self): + path = self.get_resolved_path() + if path: + return os.path.basename(path) + return None + + def symfile_basename(self): + if self.symfile: + return os.path.basename(self.symfile) + return None + + def has_section_load_info(self): + return self.section_infos or self.slide is not None + + def load_module(self, target): + if self.unavailable: + return None # We already warned that we couldn't find this module, so don't return an error string + # Load this module into "target" using the section infos to + # set the section load addresses + if self.has_section_load_info(): + if target: + if self.module: + if self.section_infos: + num_sections_loaded = 0 + for section_info in self.section_infos: + if section_info.name: + section = self.module.FindSection( + section_info.name) + if section: + error = target.SetSectionLoadAddress( + section, section_info.start_addr) + if error.Success(): + num_sections_loaded += 1 + else: + return 'error: %s' % error.GetCString() + else: + return 'error: unable to find the section named "%s"' % section_info.name + else: + return 'error: unable to find "%s" section in "%s"' % ( + range.name, self.get_resolved_path()) + if num_sections_loaded == 0: + return 'error: no sections were successfully loaded' + else: + err = target.SetModuleLoadAddress( + self.module, self.slide) + if err.Fail(): + return err.GetCString() + return None + else: + return 'error: invalid module' + else: + return 'error: invalid target' + else: + return 'error: no section infos' + + def add_module(self, target): + '''Add the Image described in this object to "target" and load the sections if "load" is True.''' + if target: + # Try and find using UUID only first so that paths need not match + # up + uuid_str = self.get_normalized_uuid_string() + if uuid_str: + self.module = target.AddModule(None, None, uuid_str) + if not self.module: + self.locate_module_and_debug_symbols() + if self.unavailable: + return None + resolved_path = self.get_resolved_path() + self.module = target.AddModule( + resolved_path, self.arch, uuid_str, self.symfile) + if not self.module: + return 'error: unable to get module for (%s) "%s"' % ( + self.arch, self.get_resolved_path()) + if self.has_section_load_info(): + return self.load_module(target) + else: + return None # No sections, the module was added to the target, so success + else: + return 'error: invalid target' + + def locate_module_and_debug_symbols(self): + # By default, just use the paths that were supplied in: + # self.path + # self.resolved_path + # self.module + # self.symfile + # Subclasses can inherit from this class and override this function + self.resolved = True + return True + + def get_uuid(self): + if not self.uuid and self.module: + self.uuid = uuid.UUID(self.module.GetUUIDString()) + return self.uuid + + def get_normalized_uuid_string(self): + if self.uuid: + return str(self.uuid).upper() + return None + + def create_target(self): + '''Create a target using the information in this Image object.''' + if self.unavailable: + return None + + if self.locate_module_and_debug_symbols(): + resolved_path = self.get_resolved_path() + path_spec = lldb.SBFileSpec(resolved_path) + #result.PutCString ('plist[%s] = %s' % (uuid, self.plist)) + error = lldb.SBError() + target = lldb.debugger.CreateTarget( + resolved_path, self.arch, None, False, error) + if target: + self.module = target.FindModule(path_spec) + if self.has_section_load_info(): + err = self.load_module(target) + if err: + print 'ERROR: ', err + return target + else: + print 'error: unable to create a valid target for (%s) "%s"' % (self.arch, self.path) + else: + print 'error: unable to locate main executable (%s) "%s"' % (self.arch, self.path) + return None + + +class Symbolicator: + + def __init__(self): + """A class the represents the information needed to symbolicate addresses in a program""" + self.target = None + self.images = list() # a list of images to be used when symbolicating + self.addr_mask = 0xffffffffffffffff + + @classmethod + def InitWithSBTarget(cls, target): + obj = cls() + obj.target = target + obj.images = list() + triple = target.triple + if triple: + arch = triple.split('-')[0] + if "arm" in arch: + obj.addr_mask = 0xfffffffffffffffe + + for module in target.modules: + image = Image.InitWithSBTargetAndSBModule(target, module) + obj.images.append(image) + return obj + + def __str__(self): + s = "Symbolicator:\n" + if self.target: + s += "Target = '%s'\n" % (self.target) + s += "Target modules:\n" + for m in self.target.modules: + s += str(m) + "\n" + s += "Images:\n" + for image in self.images: + s += ' %s\n' % (image) + return s + + def find_images_with_identifier(self, identifier): + images = list() + for image in self.images: + if image.identifier == identifier: + images.append(image) + if len(images) == 0: + regex_text = '^.*\.%s$' % (re.escape(identifier)) + regex = re.compile(regex_text) + for image in self.images: + if regex.match(image.identifier): + images.append(image) + return images + + def find_image_containing_load_addr(self, load_addr): + for image in self.images: + if image.get_section_containing_load_addr(load_addr): + return image + return None + + def create_target(self): + if self.target: + return self.target + + if self.images: + for image in self.images: + self.target = image.create_target() + if self.target: + if self.target.GetAddressByteSize() == 4: + triple = self.target.triple + if triple: + arch = triple.split('-')[0] + if "arm" in arch: + self.addr_mask = 0xfffffffffffffffe + return self.target + return None + + def symbolicate(self, load_addr, verbose=False): + if not self.target: + self.create_target() + if self.target: + live_process = False + process = self.target.process + if process: + state = process.state + if state > lldb.eStateUnloaded and state < lldb.eStateDetached: + live_process = True + # If we don't have a live process, we can attempt to find the image + # that a load address belongs to and lazily load its module in the + # target, but we shouldn't do any of this if we have a live process + if not live_process: + image = self.find_image_containing_load_addr(load_addr) + if image: + image.add_module(self.target) + symbolicated_address = Address(self.target, load_addr) + if symbolicated_address.symbolicate(verbose): + if symbolicated_address.so_addr: + symbolicated_addresses = list() + symbolicated_addresses.append(symbolicated_address) + # See if we were able to reconstruct anything? + while True: + inlined_parent_so_addr = lldb.SBAddress() + inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope( + symbolicated_address.so_addr, inlined_parent_so_addr) + if not inlined_parent_sym_ctx: + break + if not inlined_parent_so_addr: + break + + symbolicated_address = Address( + self.target, inlined_parent_so_addr.GetLoadAddress( + self.target)) + symbolicated_address.sym_ctx = inlined_parent_sym_ctx + symbolicated_address.so_addr = inlined_parent_so_addr + symbolicated_address.symbolicate(verbose) + + # push the new frame onto the new frame stack + symbolicated_addresses.append(symbolicated_address) + + if symbolicated_addresses: + return symbolicated_addresses + else: + print 'error: no target in Symbolicator' + return None + + +def disassemble_instructions( + target, + instructions, + pc, + insts_before_pc, + insts_after_pc, + non_zeroeth_frame): + lines = list() + pc_index = -1 + comment_column = 50 + for inst_idx, inst in enumerate(instructions): + inst_pc = inst.GetAddress().GetLoadAddress(target) + if pc == inst_pc: + pc_index = inst_idx + mnemonic = inst.GetMnemonic(target) + operands = inst.GetOperands(target) + comment = inst.GetComment(target) + #data = inst.GetData (target) + lines.append("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands)) + if comment: + line_len = len(lines[-1]) + if line_len < comment_column: + lines[-1] += ' ' * (comment_column - line_len) + lines[-1] += "; %s" % comment + + if pc_index >= 0: + # If we are disassembling the non-zeroeth frame, we need to backup the + # PC by 1 + if non_zeroeth_frame and pc_index > 0: + pc_index = pc_index - 1 + if insts_before_pc == -1: + start_idx = 0 + else: + start_idx = pc_index - insts_before_pc + if start_idx < 0: + start_idx = 0 + if insts_before_pc == -1: + end_idx = inst_idx + else: + end_idx = pc_index + insts_after_pc + if end_idx > inst_idx: + end_idx = inst_idx + for i in range(start_idx, end_idx + 1): + if i == pc_index: + print ' -> ', lines[i] + else: + print ' ', lines[i] + + +def print_module_section_data(section): + print section + section_data = section.GetSectionData() + if section_data: + ostream = lldb.SBStream() + section_data.GetDescription(ostream, section.GetFileAddress()) + print ostream.GetData() + + +def print_module_section(section, depth): + print section + if depth > 0: + num_sub_sections = section.GetNumSubSections() + for sect_idx in range(num_sub_sections): + print_module_section( + section.GetSubSectionAtIndex(sect_idx), depth - 1) + + +def print_module_sections(module, depth): + for sect in module.section_iter(): + print_module_section(sect, depth) + + +def print_module_symbols(module): + for sym in module: + print sym + + +def Symbolicate(command_args): + + usage = "usage: %prog [options] [addr2 ...]" + description = '''Symbolicate one or more addresses using LLDB's python scripting API..''' + parser = optparse.OptionParser( + description=description, + prog='crashlog.py', + usage=usage) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='display verbose debug info', + default=False) + parser.add_option( + '-p', + '--platform', + type='string', + metavar='platform', + dest='platform', + help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') + parser.add_option( + '-f', + '--file', + type='string', + metavar='file', + dest='file', + help='Specify a file to use when symbolicating') + parser.add_option( + '-a', + '--arch', + type='string', + metavar='arch', + dest='arch', + help='Specify a architecture to use when symbolicating') + parser.add_option( + '-s', + '--slide', + type='int', + metavar='slide', + dest='slide', + help='Specify the slide to use on the file specified with the --file option', + default=None) + parser.add_option( + '--section', + type='string', + action='append', + dest='section_strings', + help='specify = or =-') + try: + (options, args) = parser.parse_args(command_args) + except: + return + symbolicator = Symbolicator() + images = list() + if options.file: + image = Image(options.file) + image.arch = options.arch + # Add any sections that were specified with one or more --section + # options + if options.section_strings: + for section_str in options.section_strings: + section = Section() + if section.set_from_string(section_str): + image.add_section(section) + else: + sys.exit(1) + if options.slide is not None: + image.slide = options.slide + symbolicator.images.append(image) + + target = symbolicator.create_target() + if options.verbose: + print symbolicator + if target: + for addr_str in args: + addr = int(addr_str, 0) + symbolicated_addrs = symbolicator.symbolicate( + addr, options.verbose) + for symbolicated_addr in symbolicated_addrs: + print symbolicated_addr + print + else: + print 'error: no target for %s' % (symbolicator) + +if __name__ == '__main__': + # Create a new debugger instance + lldb.debugger = lldb.SBDebugger.Create() + Symbolicate(sys.argv[1:]) diff --git a/examples/python/types.py b/examples/python/types.py new file mode 100755 index 000000000..a8aac24f4 --- /dev/null +++ b/examples/python/types.py @@ -0,0 +1,356 @@ +#!/usr/bin/python + +#---------------------------------------------------------------------- +# Be sure to add the python path that points to the LLDB shared library. +# +# # To use this in the embedded python interpreter using "lldb" just +# import it with the full path using the "command script import" +# command +# (lldb) command script import /path/to/cmdtemplate.py +#---------------------------------------------------------------------- + +import commands +import platform +import os +import re +import signal +import sys + +try: + # Just try for LLDB in case PYTHONPATH is already correctly setup + import lldb +except ImportError: + lldb_python_dirs = list() + # lldb is not in the PYTHONPATH, try some defaults for the current platform + platform_system = platform.system() + if platform_system == 'Darwin': + # On Darwin, try the currently selected Xcode directory + xcode_dir = commands.getoutput("xcode-select --print-path") + if xcode_dir: + lldb_python_dirs.append( + os.path.realpath( + xcode_dir + + '/../SharedFrameworks/LLDB.framework/Resources/Python')) + lldb_python_dirs.append( + xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + lldb_python_dirs.append( + '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') + success = False + for lldb_python_dir in lldb_python_dirs: + if os.path.exists(lldb_python_dir): + if not (sys.path.__contains__(lldb_python_dir)): + sys.path.append(lldb_python_dir) + try: + import lldb + except ImportError: + pass + else: + print 'imported lldb from: "%s"' % (lldb_python_dir) + success = True + break + if not success: + print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" + sys.exit(1) + +import commands +import optparse +import shlex +import time + + +def regex_option_callback(option, opt_str, value, parser): + if opt_str == "--std": + value = '^std::' + regex = re.compile(value) + parser.values.skip_type_regexes.append(regex) + + +def create_types_options(for_lldb_command): + if for_lldb_command: + usage = "usage: %prog [options]" + description = '''This command will help check for padding in between +base classes and members in structs and classes. It will summarize the types +and how much padding was found. If no types are specified with the --types TYPENAME +option, all structure and class types will be verified. If no modules are +specified with the --module option, only the target's main executable will be +searched. +''' + else: + usage = "usage: %prog [options] EXEPATH [EXEPATH ...]" + description = '''This command will help check for padding in between +base classes and members in structures and classes. It will summarize the types +and how much padding was found. One or more paths to executable files must be +specified and targets will be created with these modules. If no types are +specified with the --types TYPENAME option, all structure and class types will +be verified in all specified modules. +''' + parser = optparse.OptionParser( + description=description, + prog='framestats', + usage=usage) + if not for_lldb_command: + parser.add_option( + '-a', + '--arch', + type='string', + dest='arch', + help='The architecture to use when creating the debug target.', + default=None) + parser.add_option( + '-p', + '--platform', + type='string', + metavar='platform', + dest='platform', + help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') + parser.add_option( + '-m', + '--module', + action='append', + type='string', + metavar='MODULE', + dest='modules', + help='Specify one or more modules which will be used to verify the types.', + default=[]) + parser.add_option( + '-d', + '--debug', + action='store_true', + dest='debug', + help='Pause 10 seconds to wait for a debugger to attach.', + default=False) + parser.add_option( + '-t', + '--type', + action='append', + type='string', + metavar='TYPENAME', + dest='typenames', + help='Specify one or more type names which should be verified. If no type names are specified, all class and struct types will be verified.', + default=[]) + parser.add_option( + '-v', + '--verbose', + action='store_true', + dest='verbose', + help='Enable verbose logging and information.', + default=False) + parser.add_option( + '-s', + '--skip-type-regex', + action="callback", + callback=regex_option_callback, + type='string', + metavar='REGEX', + dest='skip_type_regexes', + help='Regular expressions that, if they match the current member typename, will cause the type to no be recursively displayed.', + default=[]) + parser.add_option( + '--std', + action="callback", + callback=regex_option_callback, + metavar='REGEX', + dest='skip_type_regexes', + help="Don't' recurse into types in the std namespace.", + default=[]) + return parser + + +def verify_type(target, options, type): + print type + typename = type.GetName() + # print 'type: %s' % (typename) + (end_offset, padding) = verify_type_recursive( + target, options, type, None, 0, 0, 0) + byte_size = type.GetByteSize() + # if end_offset < byte_size: + # last_member_padding = byte_size - end_offset + # print '%+4u <%u> padding' % (end_offset, last_member_padding) + # padding += last_member_padding + print 'Total byte size: %u' % (byte_size) + print 'Total pad bytes: %u' % (padding) + if padding > 0: + print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0) + print + + +def verify_type_recursive( + target, + options, + type, + member_name, + depth, + base_offset, + padding): + prev_end_offset = base_offset + typename = type.GetName() + byte_size = type.GetByteSize() + if member_name and member_name != typename: + print '%+4u <%3u> %s%s %s;' % (base_offset, byte_size, ' ' * depth, typename, member_name) + else: + print '%+4u {%3u} %s%s' % (base_offset, byte_size, ' ' * depth, typename) + + for type_regex in options.skip_type_regexes: + match = type_regex.match(typename) + if match: + return (base_offset + byte_size, padding) + + members = type.members + if members: + for member_idx, member in enumerate(members): + member_type = member.GetType() + member_canonical_type = member_type.GetCanonicalType() + member_type_class = member_canonical_type.GetTypeClass() + member_name = member.GetName() + member_offset = member.GetOffsetInBytes() + member_total_offset = member_offset + base_offset + member_byte_size = member_type.GetByteSize() + member_is_class_or_struct = False + if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass: + member_is_class_or_struct = True + if member_idx == 0 and member_offset == target.GetAddressByteSize( + ) and type.IsPolymorphicClass(): + ptr_size = target.GetAddressByteSize() + print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1)) + prev_end_offset = ptr_size + else: + if prev_end_offset < member_total_offset: + member_padding = member_total_offset - prev_end_offset + padding = padding + member_padding + print '%+4u <%3u> %s' % (prev_end_offset, member_padding, ' ' * (depth + 1)) + + if member_is_class_or_struct: + (prev_end_offset, + padding) = verify_type_recursive(target, + options, + member_canonical_type, + member_name, + depth + 1, + member_total_offset, + padding) + else: + prev_end_offset = member_total_offset + member_byte_size + member_typename = member_type.GetName() + if member.IsBitfield(): + print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member.GetBitfieldSizeInBits(), member_name) + else: + print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member_name) + + if prev_end_offset < byte_size: + last_member_padding = byte_size - prev_end_offset + print '%+4u <%3u> %s' % (prev_end_offset, last_member_padding, ' ' * (depth + 1)) + padding += last_member_padding + else: + if type.IsPolymorphicClass(): + ptr_size = target.GetAddressByteSize() + print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1)) + prev_end_offset = ptr_size + prev_end_offset = base_offset + byte_size + + return (prev_end_offset, padding) + + +def check_padding_command(debugger, command, result, dict): + # Use the Shell Lexer to properly parse up command options just like a + # shell would + command_args = shlex.split(command) + parser = create_types_options(True) + try: + (options, args) = parser.parse_args(command_args) + except: + # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit + # (courtesy of OptParse dealing with argument errors by throwing SystemExit) + result.SetStatus(lldb.eReturnStatusFailed) + # returning a string is the same as returning an error whose + # description is the string + return "option parsing failed" + verify_types(debugger.GetSelectedTarget(), options) + + +@lldb.command("parse_all_struct_class_types") +def parse_all_struct_class_types(debugger, command, result, dict): + command_args = shlex.split(command) + for f in command_args: + error = lldb.SBError() + target = debugger.CreateTarget(f, None, None, False, error) + module = target.GetModuleAtIndex(0) + print "Parsing all types in '%s'" % (module) + types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct) + for t in types: + print t + print "" + + +def verify_types(target, options): + + if not target: + print 'error: invalid target' + return + + modules = list() + if len(options.modules) == 0: + # Append just the main executable if nothing was specified + module = target.modules[0] + if module: + modules.append(module) + else: + for module_name in options.modules: + module = lldb.target.module[module_name] + if module: + modules.append(module) + + if modules: + for module in modules: + print 'module: %s' % (module.file) + if options.typenames: + for typename in options.typenames: + types = module.FindTypes(typename) + if types.GetSize(): + print 'Found %u types matching "%s" in "%s"' % (len(types), typename, module.file) + for type in types: + verify_type(target, options, type) + else: + print 'error: no type matches "%s" in "%s"' % (typename, module.file) + else: + types = module.GetTypes( + lldb.eTypeClassClass | lldb.eTypeClassStruct) + print 'Found %u types in "%s"' % (len(types), module.file) + for type in types: + verify_type(target, options, type) + else: + print 'error: no modules' + +if __name__ == '__main__': + debugger = lldb.SBDebugger.Create() + parser = create_types_options(False) + + # try: + (options, args) = parser.parse_args(sys.argv[1:]) + # except: + # print "error: option parsing failed" + # sys.exit(1) + + if options.debug: + print "Waiting for debugger to attach to process %d" % os.getpid() + os.kill(os.getpid(), signal.SIGSTOP) + + for path in args: + # in a command - the lldb.* convenience variables are not to be used + # and their values (if any) are undefined + # this is the best practice to access those objects from within a + # command + error = lldb.SBError() + target = debugger.CreateTarget(path, + options.arch, + options.platform, + True, + error) + if error.Fail(): + print error.GetCString() + continue + verify_types(target, options) + +elif getattr(lldb, 'debugger', None): + lldb.debugger.HandleCommand( + 'command script add -f types.check_padding_command check_padding') + print '"check_padding" command installed, use the "--help" option for detailed help' diff --git a/examples/python/x86_64_linux_target_definition.py b/examples/python/x86_64_linux_target_definition.py new file mode 100644 index 000000000..9417b21ab --- /dev/null +++ b/examples/python/x86_64_linux_target_definition.py @@ -0,0 +1,775 @@ +#!/usr/bin/python +#===-- x86_64_linux_target_definition.py -----------------------------*- C++ -*-===// +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===// + +#---------------------------------------------------------------------- +# DESCRIPTION +# +# This file can be used with the following setting: +# plugin.process.gdb-remote.target-definition-file +# This setting should be used when you are trying to connect to a +# remote GDB server that doesn't support any of the register discovery +# packets that LLDB normally uses. +# +# Why is this necessary? LLDB doesn't require a new build of LLDB that +# targets each new architecture you will debug with. Instead, all +# architectures are supported and LLDB relies on extra GDB server +# packets to discover the target we are connecting to so that is can +# show the right registers for each target. This allows the GDB server +# to change and add new registers without requiring a new LLDB build +# just so we can see new registers. +# +# This file implements the x86_64 registers for the darwin version of +# GDB and allows you to connect to servers that use this register set. +# +# USAGE +# +# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_linux_target_definition.py +# (lldb) gdb-remote other.baz.com:1234 +# +# The target definition file will get used if and only if the +# qRegisterInfo packets are not supported when connecting to a remote +# GDB server. +#---------------------------------------------------------------------- +from lldb import * + +# Compiler and DWARF register numbers +name_to_gcc_dwarf_regnum = { + 'rax': 0, + 'rdx': 1, + 'rcx': 2, + 'rbx': 3, + 'rsi': 4, + 'rdi': 5, + 'rbp': 6, + 'rsp': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15, + 'rip': 16, + 'xmm0': 17, + 'xmm1': 18, + 'xmm2': 19, + 'xmm3': 20, + 'xmm4': 21, + 'xmm5': 22, + 'xmm6': 23, + 'xmm7': 24, + 'xmm8': 25, + 'xmm9': 26, + 'xmm10': 27, + 'xmm11': 28, + 'xmm12': 29, + 'xmm13': 30, + 'xmm14': 31, + 'xmm15': 32, + 'stmm0': 33, + 'stmm1': 34, + 'stmm2': 35, + 'stmm3': 36, + 'stmm4': 37, + 'stmm5': 38, + 'stmm6': 39, + 'stmm7': 30, + 'ymm0': 41, + 'ymm1': 42, + 'ymm2': 43, + 'ymm3': 44, + 'ymm4': 45, + 'ymm5': 46, + 'ymm6': 47, + 'ymm7': 48, + 'ymm8': 49, + 'ymm9': 40, + 'ymm10': 41, + 'ymm11': 42, + 'ymm12': 43, + 'ymm13': 44, + 'ymm14': 45, + 'ymm15': 46 +} + +name_to_gdb_regnum = { + 'rax': 0, + 'rbx': 1, + 'rcx': 2, + 'rdx': 3, + 'rsi': 4, + 'rdi': 5, + 'rbp': 6, + 'rsp': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15, + 'rip': 16, + 'rflags': 17, + 'cs': 18, + 'ss': 19, + 'ds': 20, + 'es': 21, + 'fs': 22, + 'gs': 23, + 'stmm0': 24, + 'stmm1': 25, + 'stmm2': 26, + 'stmm3': 27, + 'stmm4': 28, + 'stmm5': 29, + 'stmm6': 30, + 'stmm7': 31, + 'fctrl': 32, + 'fstat': 33, + 'ftag': 34, + 'fiseg': 35, + 'fioff': 36, + 'foseg': 37, + 'fooff': 38, + 'fop': 39, + 'xmm0': 40, + 'xmm1': 41, + 'xmm2': 42, + 'xmm3': 43, + 'xmm4': 44, + 'xmm5': 45, + 'xmm6': 46, + 'xmm7': 47, + 'xmm8': 48, + 'xmm9': 49, + 'xmm10': 50, + 'xmm11': 51, + 'xmm12': 52, + 'xmm13': 53, + 'xmm14': 54, + 'xmm15': 55, + 'mxcsr': 56, + 'ymm0': 57, + 'ymm1': 58, + 'ymm2': 59, + 'ymm3': 60, + 'ymm4': 61, + 'ymm5': 62, + 'ymm6': 63, + 'ymm7': 64, + 'ymm8': 65, + 'ymm9': 66, + 'ymm10': 67, + 'ymm11': 68, + 'ymm12': 69, + 'ymm13': 70, + 'ymm14': 71, + 'ymm15': 72 +} + +name_to_generic_regnum = { + 'rip': LLDB_REGNUM_GENERIC_PC, + 'rsp': LLDB_REGNUM_GENERIC_SP, + 'rbp': LLDB_REGNUM_GENERIC_FP, + 'rdi': LLDB_REGNUM_GENERIC_ARG1, + 'rsi': LLDB_REGNUM_GENERIC_ARG2, + 'rdx': LLDB_REGNUM_GENERIC_ARG3, + 'rcx': LLDB_REGNUM_GENERIC_ARG4, + 'r8': LLDB_REGNUM_GENERIC_ARG5, + 'r9': LLDB_REGNUM_GENERIC_ARG6 +} + + +def get_reg_num(reg_num_dict, reg_name): + if reg_name in reg_num_dict: + return reg_num_dict[reg_name] + return LLDB_INVALID_REGNUM + +x86_64_register_infos = [ + {'name': 'rax', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rbx', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rcx', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg4'}, + {'name': 'rdx', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg3'}, + {'name': 'rsi', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg2'}, + {'name': 'rdi', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg1'}, + {'name': 'rbp', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'fp'}, + {'name': 'rsp', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'sp'}, + {'name': 'r8', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg5'}, + {'name': 'r9', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg6'}, + {'name': 'r10', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r11', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r12', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r13', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r14', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r15', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rip', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'pc'}, + {'name': 'rflags', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'cs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ss', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ds', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'es', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'gs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'stmm0', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm1', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm2', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm3', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm4', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm5', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm6', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm7', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'fctrl', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fstat', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ftag', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fiseg', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fioff', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'foseg', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fooff', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fop', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'xmm0', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm1', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm2', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm3', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm4', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm5', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm6', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm7', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm8', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm9', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm10', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm11', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm12', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm13', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm14', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm15', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'mxcsr', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'orig_rax', 'set': 1, 'bitsize': 64, + 'encoding': eEncodingUint, 'format': eFormatHex}, + # Registers that are contained in or composed of one of more other + # registers + {'name': 'eax', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[31:0]'}, + {'name': 'ebx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[31:0]'}, + {'name': 'ecx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[31:0]'}, + {'name': 'edx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[31:0]'}, + {'name': 'edi', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[31:0]'}, + {'name': 'esi', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[31:0]'}, + {'name': 'ebp', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[31:0]'}, + {'name': 'esp', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[31:0]'}, + {'name': 'r8d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[31:0]'}, + {'name': 'r9d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[31:0]'}, + {'name': 'r10d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[31:0]'}, + {'name': 'r11d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[31:0]'}, + {'name': 'r12d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[31:0]'}, + {'name': 'r13d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[31:0]'}, + {'name': 'r14d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[31:0]'}, + {'name': 'r15d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[31:0]'}, + + {'name': 'ax', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[15:0]'}, + {'name': 'bx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[15:0]'}, + {'name': 'cx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[15:0]'}, + {'name': 'dx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[15:0]'}, + {'name': 'di', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[15:0]'}, + {'name': 'si', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[15:0]'}, + {'name': 'bp', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[15:0]'}, + {'name': 'sp', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[15:0]'}, + {'name': 'r8w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[15:0]'}, + {'name': 'r9w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[15:0]'}, + {'name': 'r10w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[15:0]'}, + {'name': 'r11w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[15:0]'}, + {'name': 'r12w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[15:0]'}, + {'name': 'r13w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[15:0]'}, + {'name': 'r14w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[15:0]'}, + {'name': 'r15w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[15:0]'}, + + {'name': 'ah', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[15:8]'}, + {'name': 'bh', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[15:8]'}, + {'name': 'ch', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[15:8]'}, + {'name': 'dh', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[15:8]'}, + + {'name': 'al', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[7:0]'}, + {'name': 'bl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[7:0]'}, + {'name': 'cl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[7:0]'}, + {'name': 'dl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[7:0]'}, + {'name': 'dil', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[7:0]'}, + {'name': 'sil', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[7:0]'}, + {'name': 'bpl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[7:0]'}, + {'name': 'spl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[7:0]'}, + {'name': 'r8l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[7:0]'}, + {'name': 'r9l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[7:0]'}, + {'name': 'r10l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[7:0]'}, + {'name': 'r11l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[7:0]'}, + {'name': 'r12l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[7:0]'}, + {'name': 'r13l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[7:0]'}, + {'name': 'r14l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[7:0]'}, + {'name': 'r15l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[7:0]'}, +] + +g_target_definition = None + + +def get_target_definition(): + global g_target_definition + if g_target_definition is None: + g_target_definition = {} + offset = 0 + for reg_info in x86_64_register_infos: + reg_name = reg_info['name'] + + # Only fill in the offset if there is no 'slice' in the register + # info + if 'slice' not in reg_info and 'composite' not in reg_info: + reg_info['offset'] = offset + offset += reg_info['bitsize'] / 8 + + # Set the GCC/DWARF register number for this register if it has one + reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['gcc'] = reg_num + reg_info['dwarf'] = reg_num + + # Set the generic register number for this register if it has one + reg_num = get_reg_num(name_to_generic_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['generic'] = reg_num + + # Set the GDB register number for this register if it has one + reg_num = get_reg_num(name_to_gdb_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['gdb'] = reg_num + + g_target_definition['sets'] = [ + 'General Purpose Registers', + 'Floating Point Registers'] + g_target_definition['registers'] = x86_64_register_infos + g_target_definition[ + 'host-info'] = {'triple': 'x86_64-*-linux', 'endian': eByteOrderLittle} + g_target_definition['g-packet-size'] = offset + g_target_definition['breakpoint-pc-offset'] = -1 + return g_target_definition + + +def get_dynamic_setting(target, setting_name): + if setting_name == 'gdb-server-target-definition': + return get_target_definition() diff --git a/examples/python/x86_64_qemu_target_definition.py b/examples/python/x86_64_qemu_target_definition.py new file mode 100644 index 000000000..5b4ea480c --- /dev/null +++ b/examples/python/x86_64_qemu_target_definition.py @@ -0,0 +1,773 @@ +#!/usr/bin/python +#===-- x86_64_qemu_target_definition.py -----------------------------*- C++ -*-===// +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===// + +#---------------------------------------------------------------------- +# DESCRIPTION +# +# This file can be used with the following setting: +# plugin.process.gdb-remote.target-definition-file +# This setting should be used when you are trying to connect to a +# remote GDB server that doesn't support any of the register discovery +# packets that LLDB normally uses. +# +# Why is this necessary? LLDB doesn't require a new build of LLDB that +# targets each new architecture you will debug with. Instead, all +# architectures are supported and LLDB relies on extra GDB server +# packets to discover the target we are connecting to so that is can +# show the right registers for each target. This allows the remote stub +# to change and add new registers without requiring a new LLDB build +# just so we can see new registers. +# +# This file implements the x86_64 registers for the user mode qemu on linux. +# The only difference with the Linux file is the absense of orig_rax register. +# +# USAGE +# +# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_qemu_target_definition.py +# (lldb) gdb-remote other.baz.com:1234 +# +# The target definition file will get used if and only if the +# qRegisterInfo packets are not supported when connecting to a remote +# GDB stub. +#---------------------------------------------------------------------- +from lldb import * + +# Compiler and DWARF register numbers +name_to_gcc_dwarf_regnum = { + 'rax': 0, + 'rdx': 1, + 'rcx': 2, + 'rbx': 3, + 'rsi': 4, + 'rdi': 5, + 'rbp': 6, + 'rsp': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15, + 'rip': 16, + 'xmm0': 17, + 'xmm1': 18, + 'xmm2': 19, + 'xmm3': 20, + 'xmm4': 21, + 'xmm5': 22, + 'xmm6': 23, + 'xmm7': 24, + 'xmm8': 25, + 'xmm9': 26, + 'xmm10': 27, + 'xmm11': 28, + 'xmm12': 29, + 'xmm13': 30, + 'xmm14': 31, + 'xmm15': 32, + 'stmm0': 33, + 'stmm1': 34, + 'stmm2': 35, + 'stmm3': 36, + 'stmm4': 37, + 'stmm5': 38, + 'stmm6': 39, + 'stmm7': 30, + 'ymm0': 41, + 'ymm1': 42, + 'ymm2': 43, + 'ymm3': 44, + 'ymm4': 45, + 'ymm5': 46, + 'ymm6': 47, + 'ymm7': 48, + 'ymm8': 49, + 'ymm9': 40, + 'ymm10': 41, + 'ymm11': 42, + 'ymm12': 43, + 'ymm13': 44, + 'ymm14': 45, + 'ymm15': 46 +} + +name_to_gdb_regnum = { + 'rax': 0, + 'rbx': 1, + 'rcx': 2, + 'rdx': 3, + 'rsi': 4, + 'rdi': 5, + 'rbp': 6, + 'rsp': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15, + 'rip': 16, + 'rflags': 17, + 'cs': 18, + 'ss': 19, + 'ds': 20, + 'es': 21, + 'fs': 22, + 'gs': 23, + 'stmm0': 24, + 'stmm1': 25, + 'stmm2': 26, + 'stmm3': 27, + 'stmm4': 28, + 'stmm5': 29, + 'stmm6': 30, + 'stmm7': 31, + 'fctrl': 32, + 'fstat': 33, + 'ftag': 34, + 'fiseg': 35, + 'fioff': 36, + 'foseg': 37, + 'fooff': 38, + 'fop': 39, + 'xmm0': 40, + 'xmm1': 41, + 'xmm2': 42, + 'xmm3': 43, + 'xmm4': 44, + 'xmm5': 45, + 'xmm6': 46, + 'xmm7': 47, + 'xmm8': 48, + 'xmm9': 49, + 'xmm10': 50, + 'xmm11': 51, + 'xmm12': 52, + 'xmm13': 53, + 'xmm14': 54, + 'xmm15': 55, + 'mxcsr': 56, + 'ymm0': 57, + 'ymm1': 58, + 'ymm2': 59, + 'ymm3': 60, + 'ymm4': 61, + 'ymm5': 62, + 'ymm6': 63, + 'ymm7': 64, + 'ymm8': 65, + 'ymm9': 66, + 'ymm10': 67, + 'ymm11': 68, + 'ymm12': 69, + 'ymm13': 70, + 'ymm14': 71, + 'ymm15': 72 +} + +name_to_generic_regnum = { + 'rip': LLDB_REGNUM_GENERIC_PC, + 'rsp': LLDB_REGNUM_GENERIC_SP, + 'rbp': LLDB_REGNUM_GENERIC_FP, + 'rdi': LLDB_REGNUM_GENERIC_ARG1, + 'rsi': LLDB_REGNUM_GENERIC_ARG2, + 'rdx': LLDB_REGNUM_GENERIC_ARG3, + 'rcx': LLDB_REGNUM_GENERIC_ARG4, + 'r8': LLDB_REGNUM_GENERIC_ARG5, + 'r9': LLDB_REGNUM_GENERIC_ARG6 +} + + +def get_reg_num(reg_num_dict, reg_name): + if reg_name in reg_num_dict: + return reg_num_dict[reg_name] + return LLDB_INVALID_REGNUM + +x86_64_register_infos = [ + {'name': 'rax', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rbx', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rcx', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg4'}, + {'name': 'rdx', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg3'}, + {'name': 'rsi', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg2'}, + {'name': 'rdi', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg1'}, + {'name': 'rbp', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'fp'}, + {'name': 'rsp', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'sp'}, + {'name': 'r8', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg5'}, + {'name': 'r9', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg6'}, + {'name': 'r10', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r11', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r12', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r13', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r14', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r15', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rip', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'pc'}, + {'name': 'rflags', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'cs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ss', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ds', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'es', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'gs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'stmm0', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm1', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm2', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm3', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm4', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm5', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm6', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm7', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'fctrl', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fstat', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ftag', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fiseg', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fioff', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'foseg', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fooff', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fop', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'xmm0', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm1', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm2', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm3', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm4', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm5', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm6', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm7', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm8', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm9', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm10', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm11', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm12', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm13', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm14', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm15', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'mxcsr', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + # Registers that are contained in or composed of one of more other + # registers + {'name': 'eax', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[31:0]'}, + {'name': 'ebx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[31:0]'}, + {'name': 'ecx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[31:0]'}, + {'name': 'edx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[31:0]'}, + {'name': 'edi', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[31:0]'}, + {'name': 'esi', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[31:0]'}, + {'name': 'ebp', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[31:0]'}, + {'name': 'esp', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[31:0]'}, + {'name': 'r8d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[31:0]'}, + {'name': 'r9d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[31:0]'}, + {'name': 'r10d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[31:0]'}, + {'name': 'r11d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[31:0]'}, + {'name': 'r12d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[31:0]'}, + {'name': 'r13d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[31:0]'}, + {'name': 'r14d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[31:0]'}, + {'name': 'r15d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[31:0]'}, + + {'name': 'ax', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[15:0]'}, + {'name': 'bx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[15:0]'}, + {'name': 'cx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[15:0]'}, + {'name': 'dx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[15:0]'}, + {'name': 'di', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[15:0]'}, + {'name': 'si', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[15:0]'}, + {'name': 'bp', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[15:0]'}, + {'name': 'sp', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[15:0]'}, + {'name': 'r8w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[15:0]'}, + {'name': 'r9w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[15:0]'}, + {'name': 'r10w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[15:0]'}, + {'name': 'r11w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[15:0]'}, + {'name': 'r12w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[15:0]'}, + {'name': 'r13w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[15:0]'}, + {'name': 'r14w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[15:0]'}, + {'name': 'r15w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[15:0]'}, + + {'name': 'ah', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[15:8]'}, + {'name': 'bh', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[15:8]'}, + {'name': 'ch', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[15:8]'}, + {'name': 'dh', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[15:8]'}, + + {'name': 'al', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[7:0]'}, + {'name': 'bl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[7:0]'}, + {'name': 'cl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[7:0]'}, + {'name': 'dl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[7:0]'}, + {'name': 'dil', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[7:0]'}, + {'name': 'sil', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[7:0]'}, + {'name': 'bpl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[7:0]'}, + {'name': 'spl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[7:0]'}, + {'name': 'r8l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[7:0]'}, + {'name': 'r9l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[7:0]'}, + {'name': 'r10l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[7:0]'}, + {'name': 'r11l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[7:0]'}, + {'name': 'r12l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[7:0]'}, + {'name': 'r13l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[7:0]'}, + {'name': 'r14l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[7:0]'}, + {'name': 'r15l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[7:0]'}, +] + +g_target_definition = None + + +def get_target_definition(): + global g_target_definition + if g_target_definition is None: + g_target_definition = {} + offset = 0 + for reg_info in x86_64_register_infos: + reg_name = reg_info['name'] + + # Only fill in the offset if there is no 'slice' in the register + # info + if 'slice' not in reg_info and 'composite' not in reg_info: + reg_info['offset'] = offset + offset += reg_info['bitsize'] / 8 + + # Set the GCC/DWARF register number for this register if it has one + reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['gcc'] = reg_num + reg_info['dwarf'] = reg_num + + # Set the generic register number for this register if it has one + reg_num = get_reg_num(name_to_generic_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['generic'] = reg_num + + # Set the GDB register number for this register if it has one + reg_num = get_reg_num(name_to_gdb_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['gdb'] = reg_num + + g_target_definition['sets'] = [ + 'General Purpose Registers', + 'Floating Point Registers'] + g_target_definition['registers'] = x86_64_register_infos + g_target_definition[ + 'host-info'] = {'triple': 'x86_64-*-linux', 'endian': eByteOrderLittle} + g_target_definition['g-packet-size'] = offset + g_target_definition['breakpoint-pc-offset'] = -1 + return g_target_definition + + +def get_dynamic_setting(target, setting_name): + if setting_name == 'gdb-server-target-definition': + return get_target_definition() diff --git a/examples/python/x86_64_target_definition.py b/examples/python/x86_64_target_definition.py new file mode 100644 index 000000000..03411cf07 --- /dev/null +++ b/examples/python/x86_64_target_definition.py @@ -0,0 +1,778 @@ +#!/usr/bin/python +#===-- x86_64_target_definition.py -----------------------------*- C++ -*-===// +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===// + +#---------------------------------------------------------------------- +# DESCRIPTION +# +# This file can be used with the following setting: +# plugin.process.gdb-remote.target-definition-file +# This setting should be used when you are trying to connect to a +# remote GDB server that doesn't support any of the register discovery +# packets that LLDB normally uses. +# +# Why is this necessary? LLDB doesn't require a new build of LLDB that +# targets each new architecture you will debug with. Instead, all +# architectures are supported and LLDB relies on extra GDB server +# packets to discover the target we are connecting to so that is can +# show the right registers for each target. This allows the GDB server +# to change and add new registers without requiring a new LLDB build +# just so we can see new registers. +# +# This file implements the x86_64 registers for the darwin version of +# GDB and allows you to connect to servers that use this register set. +# +# USAGE +# +# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_target_definition.py +# (lldb) gdb-remote other.baz.com:1234 +# +# The target definition file will get used if and only if the +# qRegisterInfo packets are not supported when connecting to a remote +# GDB server. +#---------------------------------------------------------------------- +from lldb import * + +# Compiler and DWARF register numbers +name_to_gcc_dwarf_regnum = { + 'rax': 0, + 'rdx': 1, + 'rcx': 2, + 'rbx': 3, + 'rsi': 4, + 'rdi': 5, + 'rbp': 6, + 'rsp': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15, + 'rip': 16, + 'xmm0': 17, + 'xmm1': 18, + 'xmm2': 19, + 'xmm3': 20, + 'xmm4': 21, + 'xmm5': 22, + 'xmm6': 23, + 'xmm7': 24, + 'xmm8': 25, + 'xmm9': 26, + 'xmm10': 27, + 'xmm11': 28, + 'xmm12': 29, + 'xmm13': 30, + 'xmm14': 31, + 'xmm15': 32, + 'stmm0': 33, + 'stmm1': 34, + 'stmm2': 35, + 'stmm3': 36, + 'stmm4': 37, + 'stmm5': 38, + 'stmm6': 39, + 'stmm7': 30, + 'ymm0': 41, + 'ymm1': 42, + 'ymm2': 43, + 'ymm3': 44, + 'ymm4': 45, + 'ymm5': 46, + 'ymm6': 47, + 'ymm7': 48, + 'ymm8': 49, + 'ymm9': 40, + 'ymm10': 41, + 'ymm11': 42, + 'ymm12': 43, + 'ymm13': 44, + 'ymm14': 45, + 'ymm15': 46 +} + +name_to_gdb_regnum = { + 'rax': 0, + 'rbx': 1, + 'rcx': 2, + 'rdx': 3, + 'rsi': 4, + 'rdi': 5, + 'rbp': 6, + 'rsp': 7, + 'r8': 8, + 'r9': 9, + 'r10': 10, + 'r11': 11, + 'r12': 12, + 'r13': 13, + 'r14': 14, + 'r15': 15, + 'rip': 16, + 'rflags': 17, + 'cs': 18, + 'ss': 19, + 'ds': 20, + 'es': 21, + 'fs': 22, + 'gs': 23, + 'stmm0': 24, + 'stmm1': 25, + 'stmm2': 26, + 'stmm3': 27, + 'stmm4': 28, + 'stmm5': 29, + 'stmm6': 30, + 'stmm7': 31, + 'fctrl': 32, + 'fstat': 33, + 'ftag': 34, + 'fiseg': 35, + 'fioff': 36, + 'foseg': 37, + 'fooff': 38, + 'fop': 39, + 'xmm0': 40, + 'xmm1': 41, + 'xmm2': 42, + 'xmm3': 43, + 'xmm4': 44, + 'xmm5': 45, + 'xmm6': 46, + 'xmm7': 47, + 'xmm8': 48, + 'xmm9': 49, + 'xmm10': 50, + 'xmm11': 51, + 'xmm12': 52, + 'xmm13': 53, + 'xmm14': 54, + 'xmm15': 55, + 'mxcsr': 56, + 'ymm0': 57, + 'ymm1': 58, + 'ymm2': 59, + 'ymm3': 60, + 'ymm4': 61, + 'ymm5': 62, + 'ymm6': 63, + 'ymm7': 64, + 'ymm8': 65, + 'ymm9': 66, + 'ymm10': 67, + 'ymm11': 68, + 'ymm12': 69, + 'ymm13': 70, + 'ymm14': 71, + 'ymm15': 72 +} + +name_to_generic_regnum = { + 'rip': LLDB_REGNUM_GENERIC_PC, + 'rsp': LLDB_REGNUM_GENERIC_SP, + 'rbp': LLDB_REGNUM_GENERIC_FP, + 'rdi': LLDB_REGNUM_GENERIC_ARG1, + 'rsi': LLDB_REGNUM_GENERIC_ARG2, + 'rdx': LLDB_REGNUM_GENERIC_ARG3, + 'rcx': LLDB_REGNUM_GENERIC_ARG4, + 'r8': LLDB_REGNUM_GENERIC_ARG5, + 'r9': LLDB_REGNUM_GENERIC_ARG6 +} + + +def get_reg_num(reg_num_dict, reg_name): + if reg_name in reg_num_dict: + return reg_num_dict[reg_name] + return LLDB_INVALID_REGNUM + + +def get_reg_num(reg_num_dict, reg_name): + if reg_name in reg_num_dict: + return reg_num_dict[reg_name] + return LLDB_INVALID_REGNUM + +x86_64_register_infos = [ + {'name': 'rax', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rbx', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rcx', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg4'}, + {'name': 'rdx', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg3'}, + {'name': 'rsi', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg2'}, + {'name': 'rdi', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg1'}, + {'name': 'rbp', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'fp'}, + {'name': 'rsp', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'sp'}, + {'name': 'r8', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg5'}, + {'name': 'r9', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'arg6'}, + {'name': 'r10', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r11', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r12', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r13', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r14', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'r15', + 'set': 0, + 'bitsize': 64, + 'encoding': eEncodingUint, + 'format': eFormatAddressInfo}, + {'name': 'rip', 'set': 0, 'bitsize': 64, 'encoding': eEncodingUint, + 'format': eFormatAddressInfo, 'alt-name': 'pc'}, + {'name': 'rflags', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'cs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ss', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ds', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'es', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'gs', 'set': 0, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'stmm0', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm1', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm2', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm3', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm4', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm5', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm6', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'stmm7', + 'set': 1, + 'bitsize': 80, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'fctrl', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fstat', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'ftag', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fiseg', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fioff', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'foseg', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fooff', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'fop', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + {'name': 'xmm0', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm1', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm2', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm3', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm4', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm5', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm6', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm7', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm8', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm9', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm10', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm11', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm12', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm13', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm14', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'xmm15', + 'set': 1, + 'bitsize': 128, + 'encoding': eEncodingVector, + 'format': eFormatVectorOfUInt8}, + {'name': 'mxcsr', 'set': 1, 'bitsize': 32, + 'encoding': eEncodingUint, 'format': eFormatHex}, + # Registers that are contained in or composed of one of more other + # registers + {'name': 'eax', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[31:0]'}, + {'name': 'ebx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[31:0]'}, + {'name': 'ecx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[31:0]'}, + {'name': 'edx', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[31:0]'}, + {'name': 'edi', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[31:0]'}, + {'name': 'esi', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[31:0]'}, + {'name': 'ebp', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[31:0]'}, + {'name': 'esp', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[31:0]'}, + {'name': 'r8d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[31:0]'}, + {'name': 'r9d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[31:0]'}, + {'name': 'r10d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[31:0]'}, + {'name': 'r11d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[31:0]'}, + {'name': 'r12d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[31:0]'}, + {'name': 'r13d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[31:0]'}, + {'name': 'r14d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[31:0]'}, + {'name': 'r15d', + 'set': 0, + 'bitsize': 32, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[31:0]'}, + + {'name': 'ax', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[15:0]'}, + {'name': 'bx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[15:0]'}, + {'name': 'cx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[15:0]'}, + {'name': 'dx', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[15:0]'}, + {'name': 'di', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[15:0]'}, + {'name': 'si', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[15:0]'}, + {'name': 'bp', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[15:0]'}, + {'name': 'sp', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[15:0]'}, + {'name': 'r8w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[15:0]'}, + {'name': 'r9w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[15:0]'}, + {'name': 'r10w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[15:0]'}, + {'name': 'r11w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[15:0]'}, + {'name': 'r12w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[15:0]'}, + {'name': 'r13w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[15:0]'}, + {'name': 'r14w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[15:0]'}, + {'name': 'r15w', + 'set': 0, + 'bitsize': 16, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[15:0]'}, + + {'name': 'ah', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[15:8]'}, + {'name': 'bh', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[15:8]'}, + {'name': 'ch', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[15:8]'}, + {'name': 'dh', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[15:8]'}, + + {'name': 'al', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rax[7:0]'}, + {'name': 'bl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbx[7:0]'}, + {'name': 'cl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rcx[7:0]'}, + {'name': 'dl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdx[7:0]'}, + {'name': 'dil', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rdi[7:0]'}, + {'name': 'sil', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsi[7:0]'}, + {'name': 'bpl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rbp[7:0]'}, + {'name': 'spl', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'rsp[7:0]'}, + {'name': 'r8l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r8[7:0]'}, + {'name': 'r9l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r9[7:0]'}, + {'name': 'r10l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r10[7:0]'}, + {'name': 'r11l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r11[7:0]'}, + {'name': 'r12l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r12[7:0]'}, + {'name': 'r13l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r13[7:0]'}, + {'name': 'r14l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r14[7:0]'}, + {'name': 'r15l', + 'set': 0, + 'bitsize': 8, + 'encoding': eEncodingUint, + 'format': eFormatHex, + 'slice': 'r15[7:0]'}, +] + +g_target_definition = None + + +def get_target_definition(): + global g_target_definition + if g_target_definition is None: + g_target_definition = {} + offset = 0 + for reg_info in x86_64_register_infos: + reg_name = reg_info['name'] + + # Only fill in the offset if there is no 'slice' in the register + # info + if 'slice' not in reg_info and 'composite' not in reg_info: + reg_info['offset'] = offset + offset += reg_info['bitsize'] / 8 + + # Set the GCC/DWARF register number for this register if it has one + reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['gcc'] = reg_num + reg_info['dwarf'] = reg_num + + # Set the generic register number for this register if it has one + reg_num = get_reg_num(name_to_generic_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['generic'] = reg_num + + # Set the GDB register number for this register if it has one + reg_num = get_reg_num(name_to_gdb_regnum, reg_name) + if reg_num != LLDB_INVALID_REGNUM: + reg_info['gdb'] = reg_num + + g_target_definition['sets'] = [ + 'General Purpose Registers', + 'Floating Point Registers'] + g_target_definition['registers'] = x86_64_register_infos + g_target_definition[ + 'host-info'] = {'triple': 'x86_64-apple-macosx', 'endian': eByteOrderLittle} + g_target_definition['g-packet-size'] = offset + return g_target_definition + + +def get_dynamic_setting(target, setting_name): + if setting_name == 'gdb-server-target-definition': + return get_target_definition() diff --git a/examples/scripting/dictionary.c b/examples/scripting/dictionary.c new file mode 100644 index 000000000..260eab486 --- /dev/null +++ b/examples/scripting/dictionary.c @@ -0,0 +1,173 @@ +//===-- dictionary.c ---------------------------------------------*- C -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +#include +#include +#include +#include + +typedef struct tree_node { + const char *word; + struct tree_node *left; + struct tree_node *right; +} tree_node; + +/* Given a char*, returns a substring that starts at the first + alphabet character and ends at the last alphabet character, i.e. it + strips off beginning or ending quotes, punctuation, etc. */ + +char *strip(char **word) { + char *start = *word; + int len = strlen(start); + char *end = start + len - 1; + + while ((start < end) && (!isalpha(start[0]))) + start++; + + while ((end > start) && (!isalpha(end[0]))) + end--; + + if (start > end) + return NULL; + + end[1] = '\0'; + *word = start; + + return start; +} + +/* Given a binary search tree (sorted alphabetically by the word at + each node), and a new word, inserts the word at the appropriate + place in the tree. */ + +void insert(tree_node *root, char *word) { + if (root == NULL) + return; + + int compare_value = strcmp(word, root->word); + + if (compare_value == 0) + return; + + if (compare_value < 0) { + if (root->left != NULL) + insert(root->left, word); + else { + tree_node *new_node = (tree_node *)malloc(sizeof(tree_node)); + new_node->word = strdup(word); + new_node->left = NULL; + new_node->right = NULL; + root->left = new_node; + } + } else { + if (root->right != NULL) + insert(root->right, word); + else { + tree_node *new_node = (tree_node *)malloc(sizeof(tree_node)); + new_node->word = strdup(word); + new_node->left = NULL; + new_node->right = NULL; + root->right = new_node; + } + } +} + +/* Read in a text file and storea all the words from the file in a + binary search tree. */ + +void populate_dictionary(tree_node **dictionary, char *filename) { + FILE *in_file; + char word[1024]; + + in_file = fopen(filename, "r"); + if (in_file) { + while (fscanf(in_file, "%s", word) == 1) { + char *new_word = (strdup(word)); + new_word = strip(&new_word); + if (*dictionary == NULL) { + tree_node *new_node = (tree_node *)malloc(sizeof(tree_node)); + new_node->word = new_word; + new_node->left = NULL; + new_node->right = NULL; + *dictionary = new_node; + } else + insert(*dictionary, new_word); + } + } +} + +/* Given a binary search tree and a word, search for the word + in the binary search tree. */ + +int find_word(tree_node *dictionary, char *word) { + if (!word || !dictionary) + return 0; + + int compare_value = strcmp(word, dictionary->word); + + if (compare_value == 0) + return 1; + else if (compare_value < 0) + return find_word(dictionary->left, word); + else + return find_word(dictionary->right, word); +} + +/* Print out the words in the binary search tree, in sorted order. */ + +void print_tree(tree_node *dictionary) { + if (!dictionary) + return; + + if (dictionary->left) + print_tree(dictionary->left); + + printf("%s\n", dictionary->word); + + if (dictionary->right) + print_tree(dictionary->right); +} + +int main(int argc, char **argv) { + tree_node *dictionary = NULL; + char buffer[1024]; + char *filename; + int done = 0; + + if (argc == 2) + filename = argv[1]; + + if (!filename) + return -1; + + populate_dictionary(&dictionary, filename); + fprintf(stdout, "Dictionary loaded.\nEnter search word: "); + while (!done && fgets(buffer, sizeof(buffer), stdin)) { + char *word = buffer; + int len = strlen(word); + int i; + + for (i = 0; i < len; ++i) + word[i] = tolower(word[i]); + + if ((len > 0) && (word[len - 1] == '\n')) { + word[len - 1] = '\0'; + len = len - 1; + } + + if (find_word(dictionary, word)) + fprintf(stdout, "Yes!\n"); + else + fprintf(stdout, "No!\n"); + + fprintf(stdout, "Enter search word: "); + } + + fprintf(stdout, "\n"); + return 0; +} diff --git a/examples/scripting/tree_utils.py b/examples/scripting/tree_utils.py new file mode 100755 index 000000000..a4d1645d7 --- /dev/null +++ b/examples/scripting/tree_utils.py @@ -0,0 +1,118 @@ +""" +# ===-- tree_utils.py ---------------------------------------*- Python -*-===// +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +# ===---------------------------------------------------------------------===// + +tree_utils.py - A set of functions for examining binary +search trees, based on the example search tree defined in +dictionary.c. These functions contain calls to LLDB API +functions, and assume that the LLDB Python module has been +imported. + +For a thorough explanation of how the DFS function works, and +for more information about dictionary.c go to +http://lldb.llvm.org/scripting.html +""" + + +def DFS(root, word, cur_path): + """ + Recursively traverse a binary search tree containing + words sorted alphabetically, searching for a particular + word in the tree. Also maintains a string representing + the path from the root of the tree to the current node. + If the word is found in the tree, return the path string. + Otherwise return an empty string. + + This function assumes the binary search tree is + the one defined in dictionary.c It uses LLDB API + functions to examine and traverse the tree nodes. + """ + + # Get pointer field values out of node 'root' + + root_word_ptr = root.GetChildMemberWithName("word") + left_child_ptr = root.GetChildMemberWithName("left") + right_child_ptr = root.GetChildMemberWithName("right") + + # Get the word out of the word pointer and strip off + # surrounding quotes (added by call to GetSummary). + + root_word = root_word_ptr.GetSummary() + end = len(root_word) - 1 + if root_word[0] == '"' and root_word[end] == '"': + root_word = root_word[1:end] + end = len(root_word) - 1 + if root_word[0] == '\'' and root_word[end] == '\'': + root_word = root_word[1:end] + + # Main depth first search + + if root_word == word: + return cur_path + elif word < root_word: + + # Check to see if left child is NULL + + if left_child_ptr.GetValue() is None: + return "" + else: + cur_path = cur_path + "L" + return DFS(left_child_ptr, word, cur_path) + else: + + # Check to see if right child is NULL + + if right_child_ptr.GetValue() is None: + return "" + else: + cur_path = cur_path + "R" + return DFS(right_child_ptr, word, cur_path) + + +def tree_size(root): + """ + Recursively traverse a binary search tree, counting + the nodes in the tree. Returns the final count. + + This function assumes the binary search tree is + the one defined in dictionary.c It uses LLDB API + functions to examine and traverse the tree nodes. + """ + if (root.GetValue is None): + return 0 + + if (int(root.GetValue(), 16) == 0): + return 0 + + left_size = tree_size(root.GetChildAtIndex(1)) + right_size = tree_size(root.GetChildAtIndex(2)) + + total_size = left_size + right_size + 1 + return total_size + + +def print_tree(root): + """ + Recursively traverse a binary search tree, printing out + the words at the nodes in alphabetical order (the + search order for the binary tree). + + This function assumes the binary search tree is + the one defined in dictionary.c It uses LLDB API + functions to examine and traverse the tree nodes. + """ + if (root.GetChildAtIndex(1).GetValue() is not None) and ( + int(root.GetChildAtIndex(1).GetValue(), 16) != 0): + print_tree(root.GetChildAtIndex(1)) + + print root.GetChildAtIndex(0).GetSummary() + + if (root.GetChildAtIndex(2).GetValue() is not None) and ( + int(root.GetChildAtIndex(2).GetValue(), 16) != 0): + print_tree(root.GetChildAtIndex(2)) diff --git a/examples/summaries/cocoa/CFArray.py b/examples/summaries/cocoa/CFArray.py new file mode 100644 index 000000000..6fc97081b --- /dev/null +++ b/examples/summaries/cocoa/CFArray.py @@ -0,0 +1,233 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSArray +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# much less functional than the other two cases below +# just runs code to get to the count and then returns +# no children + + +class NSArrayKVC_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + num_children_vo = self.valobj.CreateValueFromExpression( + "count", "(int)[" + stream.GetData() + " count]") + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return "" + +# much less functional than the other two cases below +# just runs code to get to the count and then returns +# no children + + +class NSArrayCF_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.ulong): + self.sys_params.types_cache.ulong = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset( + "count", self.sys_params.cfruntime_size, self.sys_params.types_cache.ulong) + return num_children_vo.GetValueAsUnsigned(0) + + +class NSArrayI_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.long): + self.sys_params.types_cache.long = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeLong) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # skip the isa pointer and get at the size + def num_children(self): + logger = lldb.formatters.Logger.Logger() + count = self.valobj.CreateChildAtOffset( + "count", + self.sys_params.pointer_size, + self.sys_params.types_cache.long) + return count.GetValueAsUnsigned(0) + + +class NSArrayM_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.long): + self.sys_params.types_cache.long = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeLong) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # skip the isa pointer and get at the size + def num_children(self): + logger = lldb.formatters.Logger.Logger() + count = self.valobj.CreateChildAtOffset( + "count", + self.sys_params.pointer_size, + self.sys_params.types_cache.long) + return count.GetValueAsUnsigned(0) + +# this is the actual synth provider, but is just a wrapper that checks +# whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an +# appropriate backend layer to do the computations + + +class NSArray_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.adjust_for_architecture() + self.error = False + self.wrapper = self.make_wrapper() + self.invalid = (self.wrapper is None) + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + if self.wrapper is None: + return 0 + return self.wrapper.num_children() + + def update(self): + logger = lldb.formatters.Logger.Logger() + if self.wrapper is None: + return + self.wrapper.update() + + # this code acts as our defense against NULL and uninitialized + # NSArray pointers, which makes it much longer than it would be otherwise + def make_wrapper(self): + logger = lldb.formatters.Logger.Logger() + if self.valobj.GetValueAsUnsigned() == 0: + self.error = True + return lldb.runtime.objc.objc_runtime.InvalidPointer_Description( + True) + else: + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + self.valobj, statistics) + if wrapper: + self.error = True + return wrapper + + name_string = class_data.class_name() + + logger >> "Class name is " + str(name_string) + + if name_string == '__NSArrayI': + wrapper = NSArrayI_SynthProvider( + self.valobj, dict, class_data.sys_params) + statistics.metric_hit('code_notrun', self.valobj.GetName()) + elif name_string == '__NSArrayM': + wrapper = NSArrayM_SynthProvider( + self.valobj, dict, class_data.sys_params) + statistics.metric_hit('code_notrun', self.valobj.GetName()) + elif name_string == '__NSCFArray': + wrapper = NSArrayCF_SynthProvider( + self.valobj, dict, class_data.sys_params) + statistics.metric_hit('code_notrun', self.valobj.GetName()) + else: + wrapper = NSArrayKVC_SynthProvider( + self.valobj, dict, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', str( + self.valobj.GetName()) + " seen as " + name_string) + return wrapper + + +def CFArray_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = NSArray_SynthProvider(valobj, dict) + if not provider.invalid: + if provider.error: + return provider.wrapper.message() + try: + summary = int(provider.num_children()) + except: + summary = None + logger >> "provider gave me " + str(summary) + if summary is None: + summary = '' + elif isinstance(summary, basestring): + pass + else: + # we format it like it were a CFString to make it look the same as + # the summary from Xcode + summary = '@"' + str(summary) + \ + (" objects" if summary != 1 else " object") + '"' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef") diff --git a/examples/summaries/cocoa/CFBag.py b/examples/summaries/cocoa/CFBag.py new file mode 100644 index 000000000..d9a18996e --- /dev/null +++ b/examples/summaries/cocoa/CFBag.py @@ -0,0 +1,163 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for CFBag +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the length for an CFBag, so they need not +# obey the interface specification for synthetic children providers + + +class CFBagRef_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # 12 bytes on i386 + # 20 bytes on x64 + # most probably 2 pointers and 4 bytes of data + def offset(self): + logger = lldb.formatters.Logger.Logger() + if self.sys_params.is_64_bit: + return 20 + else: + return 12 + + def length(self): + logger = lldb.formatters.Logger.Logger() + size = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + return size.GetValueAsUnsigned(0) + + +class CFBagUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def length(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + num_children_vo = self.valobj.CreateValueFromExpression( + "count", "(int)CFBagGetCount(" + stream.GetData() + " )") + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return "" + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + actual_name = name_string + + logger >> "name string got was " + \ + str(name_string) + " but actual name is " + str(actual_name) + + if class_data.is_cftype(): + # CFBag does not expose an actual NSWrapper type, so we have to check that this is + # an NSCFType and then check we are a pointer-to __CFBag + valobj_type = valobj.GetType() + if valobj_type.IsValid() and valobj_type.IsPointerType(): + valobj_type = valobj_type.GetPointeeType() + if valobj_type.IsValid(): + actual_name = valobj_type.GetName() + if actual_name == '__CFBag' or \ + actual_name == 'const struct __CFBag': + wrapper = CFBagRef_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + return wrapper + wrapper = CFBagUnknown_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + actual_name) + return wrapper + + +def CFBag_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.length() + except: + summary = None + logger >> "summary got from provider: " + str(summary) + # for some reason, one needs to clear some bits for the count + # to be correct when using CF(Mutable)BagRef on x64 + # the bit mask was derived through experimentation + # (if counts start looking weird, then most probably + # the mask needs to be changed) + if summary is None: + summary = '' + elif isinstance(summary, basestring): + pass + else: + if provider.sys_params.is_64_bit: + summary = summary & ~0x1fff000000000000 + if summary == 1: + summary = '@"1 value"' + else: + summary = '@"' + str(summary) + ' values"' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F CFBag.CFBag_SummaryProvider CFBagRef CFMutableBagRef") diff --git a/examples/summaries/cocoa/CFBinaryHeap.py b/examples/summaries/cocoa/CFBinaryHeap.py new file mode 100644 index 000000000..b22f2c5d4 --- /dev/null +++ b/examples/summaries/cocoa/CFBinaryHeap.py @@ -0,0 +1,161 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for CFBinaryHeap +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the length for an CFBinaryHeap, so they need not +# obey the interface specification for synthetic children providers + + +class CFBinaryHeapRef_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # 8 bytes on i386 + # 16 bytes on x64 + # most probably 2 pointers + def offset(self): + logger = lldb.formatters.Logger.Logger() + return 2 * self.sys_params.pointer_size + + def length(self): + logger = lldb.formatters.Logger.Logger() + size = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + return size.GetValueAsUnsigned(0) + + +class CFBinaryHeapUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def length(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + num_children_vo = self.valobj.CreateValueFromExpression( + "count", "(int)CFBinaryHeapGetCount(" + stream.GetData() + " )") + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + actual_name = class_data.class_name() + + logger >> "name string got was " + \ + str(name_string) + " but actual name is " + str(actual_name) + + if class_data.is_cftype(): + # CFBinaryHeap does not expose an actual NSWrapper type, so we have to check that this is + # an NSCFType and then check we are a pointer-to CFBinaryHeap + valobj_type = valobj.GetType() + if valobj_type.IsValid() and valobj_type.IsPointerType(): + valobj_type = valobj_type.GetPointeeType() + if valobj_type.IsValid(): + actual_name = valobj_type.GetName() + if actual_name == '__CFBinaryHeap': + wrapper = CFBinaryHeapRef_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + return wrapper + wrapper = CFBinaryHeapUnknown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def CFBinaryHeap_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.length() + except: + summary = None + logger >> "summary got from provider: " + str(summary) + # for some reason, one needs to clear some bits for the count + # to be correct when using CF(Mutable)BagRef on x64 + # the bit mask was derived through experimentation + # (if counts start looking weird, then most probably + # the mask needs to be changed) + if summary is None: + summary = '' + elif isinstance(summary, basestring): + pass + else: + if provider.sys_params.is_64_bit: + summary = summary & ~0x1fff000000000000 + if summary == 1: + return '@"1 item"' + else: + summary = '@"' + str(summary) + ' items"' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F CFBinaryHeap.CFBinaryHeap_SummaryProvider CFBinaryHeapRef") diff --git a/examples/summaries/cocoa/CFBitVector.py b/examples/summaries/cocoa/CFBitVector.py new file mode 100644 index 000000000..e788e625b --- /dev/null +++ b/examples/summaries/cocoa/CFBitVector.py @@ -0,0 +1,206 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# summary provider for CF(Mutable)BitVector +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +# first define some utility functions + + +def byte_index(abs_pos): + logger = lldb.formatters.Logger.Logger() + return abs_pos / 8 + + +def bit_index(abs_pos): + logger = lldb.formatters.Logger.Logger() + return abs_pos & 7 + + +def get_bit(byte, index): + logger = lldb.formatters.Logger.Logger() + if index < 0 or index > 7: + return None + return (byte >> (7 - index)) & 1 + + +def grab_array_item_data(pointer, index): + logger = lldb.formatters.Logger.Logger() + return pointer.GetPointeeData(index, 1) + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but a summary for a CF*BitVector, so they need not +# obey the interface specification for synthetic children providers + + +class CFBitVectorKnown_SummaryProvider: + + def adjust_for_architecture(self): + logger = lldb.formatters.Logger.Logger() + self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize() + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + if not(self.sys_params.types_cache.charptr): + self.sys_params.types_cache.charptr = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeChar).GetPointerType() + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # we skip the CFRuntimeBase + # then the next CFIndex is the count + # then we skip another CFIndex and then we get at a byte array + # that wraps the individual bits + + def contents(self): + logger = lldb.formatters.Logger.Logger() + count_vo = self.valobj.CreateChildAtOffset( + "count", + self.sys_params.cfruntime_size, + self.sys_params.types_cache.NSUInteger) + count = count_vo.GetValueAsUnsigned(0) + if count == 0: + return '(empty)' + + array_vo = self.valobj.CreateChildAtOffset( + "data", + self.sys_params.cfruntime_size + + 2 * + self.uiint_size, + self.sys_params.types_cache.charptr) + + data_list = [] + cur_byte_pos = None + for i in range(0, count): + if cur_byte_pos is None: + cur_byte_pos = byte_index(i) + cur_byte = grab_array_item_data(array_vo, cur_byte_pos) + cur_byte_val = cur_byte.uint8[0] + else: + byte_pos = byte_index(i) + # do not fetch the pointee data every single time through + if byte_pos != cur_byte_pos: + cur_byte_pos = byte_pos + cur_byte = grab_array_item_data(array_vo, cur_byte_pos) + cur_byte_val = cur_byte.uint8[0] + bit = get_bit(cur_byte_val, bit_index(i)) + if (i % 4) == 0: + data_list.append(' ') + if bit == 1: + data_list.append('1') + else: + data_list.append('0') + return ''.join(data_list) + + +class CFBitVectorUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def contents(self): + logger = lldb.formatters.Logger.Logger() + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + actual_name = name_string + + logger >> "name string got was " + \ + str(name_string) + " but actual name is " + str(actual_name) + + if class_data.is_cftype(): + # CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is + # an NSCFType and then check we are a pointer-to CFBitVectorRef + valobj_type = valobj.GetType() + if valobj_type.IsValid() and valobj_type.IsPointerType(): + valobj_type = valobj_type.GetPointeeType() + if valobj_type.IsValid(): + actual_name = valobj_type.GetName() + if actual_name == '__CFBitVector' or actual_name == '__CFMutableBitVector': + wrapper = CFBitVectorKnown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = CFBitVectorUnknown_SummaryProvider( + valobj, class_data.sys_params) + print actual_name + else: + wrapper = CFBitVectorUnknown_SummaryProvider( + valobj, class_data.sys_params) + print name_string + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def CFBitVector_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.contents() + except: + summary = None + logger >> "summary got from provider: " + str(summary) + if summary is None or summary == '': + summary = '' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef") diff --git a/examples/summaries/cocoa/CFDictionary.py b/examples/summaries/cocoa/CFDictionary.py new file mode 100644 index 000000000..92d804847 --- /dev/null +++ b/examples/summaries/cocoa/CFDictionary.py @@ -0,0 +1,263 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSDictionary +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the count for an NSDictionary, so they need not +# obey the interface specification for synthetic children providers + + +class NSCFDictionary_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # empirically determined on both 32 and 64bit desktop Mac OS X + # probably boils down to 2 pointers and 4 bytes of data, but + # the description of __CFDictionary is not readily available so most + # of this is guesswork, plain and simple + def offset(self): + logger = lldb.formatters.Logger.Logger() + if self.sys_params.is_64_bit: + return 20 + else: + return 12 + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + return num_children_vo.GetValueAsUnsigned(0) + + +class NSDictionaryI_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # we just need to skip the ISA and the count immediately follows + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + value = num_children_vo.GetValueAsUnsigned(0) + if value is not None: + # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity + # not sure if it is a bug or some weird sort of feature, but masking that out + # gets the count right + if self.sys_params.is_64_bit: + value = value & ~0xFC00000000000000 + else: + value = value & ~0xFC000000 + return value + + +class NSDictionaryM_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # we just need to skip the ISA and the count immediately follows + def offset(self): + return self.sys_params.pointer_size + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + value = num_children_vo.GetValueAsUnsigned(0) + if value is not None: + # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity + # not sure if it is a bug or some weird sort of feature, but masking that out + # gets the count right + if self.sys_params.is_64_bit: + value = value & ~0xFC00000000000000 + else: + value = value & ~0xFC000000 + return value + + +class NSDictionaryUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + num_children_vo = self.valobj.CreateValueFromExpression( + "count", "(int)[" + stream.GetData() + " count]") + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + + logger >> "class name is: " + str(name_string) + + if name_string == '__NSCFDictionary': + wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == '__NSDictionaryI': + wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == '__NSDictionaryM': + wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSDictionaryUnknown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def CFDictionary_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.num_children() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + return '' + if isinstance(summary, basestring): + return summary + return str(summary) + (" key/value pairs" if summary != + 1 else " key/value pair") + return 'Summary Unavailable' + + +def CFDictionary_SummaryProvider2(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.num_children() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + if isinstance(summary, basestring): + return summary + else: + # needed on OSX Mountain Lion + if provider.sys_params.is_64_bit: + summary = summary & ~0x0f1f000000000000 + summary = '@"' + str(summary) + \ + (' entries"' if summary != 1 else ' entry"') + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary") + debugger.HandleCommand( + "type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef") diff --git a/examples/summaries/cocoa/CFString.py b/examples/summaries/cocoa/CFString.py new file mode 100644 index 000000000..109d918a9 --- /dev/null +++ b/examples/summaries/cocoa/CFString.py @@ -0,0 +1,351 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example synthetic children and summary provider for CFString (and related NSString class) +# the real code is part of the LLDB core +import lldb +import lldb.runtime.objc.objc_runtime +import lldb.formatters.Logger + + +def CFString_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = CFStringSynthProvider(valobj, dict) + if not provider.invalid: + try: + summary = provider.get_child_at_index( + provider.get_child_index("content")) + if isinstance(summary, lldb.SBValue): + summary = summary.GetSummary() + else: + summary = '"' + summary + '"' + except: + summary = None + if summary is None: + summary = '' + return '@' + summary + return '' + + +def CFAttributedString_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + offset = valobj.GetTarget().GetProcess().GetAddressByteSize() + pointee = valobj.GetValueAsUnsigned(0) + summary = '' + if pointee is not None and pointee != 0: + pointee = pointee + offset + child_ptr = valobj.CreateValueFromAddress( + "string_ptr", pointee, valobj.GetType()) + child = child_ptr.CreateValueFromAddress( + "string_data", + child_ptr.GetValueAsUnsigned(), + valobj.GetType()).AddressOf() + provider = CFStringSynthProvider(child, dict) + if not provider.invalid: + try: + summary = provider.get_child_at_index( + provider.get_child_index("content")).GetSummary() + except: + summary = '' + if summary is None: + summary = '' + return '@' + summary + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F CFString.CFString_SummaryProvider NSString CFStringRef CFMutableStringRef") + debugger.HandleCommand( + "type summary add -F CFString.CFAttributedString_SummaryProvider NSAttributedString") + + +class CFStringSynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.update() + + # children other than "content" are for debugging only and must not be + # used in production code + def num_children(self): + logger = lldb.formatters.Logger.Logger() + if self.invalid: + return 0 + return 6 + + def read_unicode(self, pointer, max_len=2048): + logger = lldb.formatters.Logger.Logger() + process = self.valobj.GetTarget().GetProcess() + error = lldb.SBError() + pystr = u'' + # cannot do the read at once because the length value has + # a weird encoding. better play it safe here + while max_len > 0: + content = process.ReadMemory(pointer, 2, error) + new_bytes = bytearray(content) + b0 = new_bytes[0] + b1 = new_bytes[1] + pointer = pointer + 2 + if b0 == 0 and b1 == 0: + break + # rearrange bytes depending on endianness + # (do we really need this or is Cocoa going to + # use Windows-compatible little-endian even + # if the target is big endian?) + if self.is_little: + value = b1 * 256 + b0 + else: + value = b0 * 256 + b1 + pystr = pystr + unichr(value) + # read max_len unicode values, not max_len bytes + max_len = max_len - 1 + return pystr + + # handle the special case strings + # only use the custom code for the tested LP64 case + def handle_special(self): + logger = lldb.formatters.Logger.Logger() + if not self.is_64_bit: + # for 32bit targets, use safe ObjC code + return self.handle_unicode_string_safe() + offset = 12 + pointer = self.valobj.GetValueAsUnsigned(0) + offset + pystr = self.read_unicode(pointer) + return self.valobj.CreateValueFromExpression( + "content", "(char*)\"" + pystr.encode('utf-8') + "\"") + + # last resort call, use ObjC code to read; the final aim is to + # be able to strip this call away entirely and only do the read + # ourselves + def handle_unicode_string_safe(self): + return self.valobj.CreateValueFromExpression( + "content", "(char*)\"" + self.valobj.GetObjectDescription() + "\"") + + def handle_unicode_string(self): + logger = lldb.formatters.Logger.Logger() + # step 1: find offset + if self.inline: + pointer = self.valobj.GetValueAsUnsigned( + 0) + self.size_of_cfruntime_base() + if not self.explicit: + # untested, use the safe code path + return self.handle_unicode_string_safe() + else: + # a full pointer is skipped here before getting to the live + # data + pointer = pointer + self.pointer_size + else: + pointer = self.valobj.GetValueAsUnsigned( + 0) + self.size_of_cfruntime_base() + # read 8 bytes here and make an address out of them + try: + char_type = self.valobj.GetType().GetBasicType( + lldb.eBasicTypeChar).GetPointerType() + vopointer = self.valobj.CreateValueFromAddress( + "dummy", pointer, char_type) + pointer = vopointer.GetValueAsUnsigned(0) + except: + return self.valobj.CreateValueFromExpression( + "content", '(char*)"@\"invalid NSString\""') + # step 2: read Unicode data at pointer + pystr = self.read_unicode(pointer) + # step 3: return it + return pystr.encode('utf-8') + + def handle_inline_explicit(self): + logger = lldb.formatters.Logger.Logger() + offset = 3 * self.pointer_size + offset = offset + self.valobj.GetValueAsUnsigned(0) + return self.valobj.CreateValueFromExpression( + "content", "(char*)(" + str(offset) + ")") + + def handle_mutable_string(self): + logger = lldb.formatters.Logger.Logger() + offset = 2 * self.pointer_size + data = self.valobj.CreateChildAtOffset( + "content", offset, self.valobj.GetType().GetBasicType( + lldb.eBasicTypeChar).GetPointerType()) + data_value = data.GetValueAsUnsigned(0) + if self.explicit and self.unicode: + return self.read_unicode(data_value).encode('utf-8') + else: + data_value = data_value + 1 + return self.valobj.CreateValueFromExpression( + "content", "(char*)(" + str(data_value) + ")") + + def handle_UTF8_inline(self): + logger = lldb.formatters.Logger.Logger() + offset = self.valobj.GetValueAsUnsigned( + 0) + self.size_of_cfruntime_base() + if not self.explicit: + offset = offset + 1 + return self.valobj.CreateValueFromAddress( + "content", offset, self.valobj.GetType().GetBasicType( + lldb.eBasicTypeChar)).AddressOf() + + def handle_UTF8_not_inline(self): + logger = lldb.formatters.Logger.Logger() + offset = self.size_of_cfruntime_base() + return self.valobj.CreateChildAtOffset( + "content", offset, self.valobj.GetType().GetBasicType( + lldb.eBasicTypeChar).GetPointerType()) + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Querying for child [" + str(index) + "]" + if index == 0: + return self.valobj.CreateValueFromExpression( + "mutable", str(int(self.mutable))) + if index == 1: + return self.valobj.CreateValueFromExpression("inline", + str(int(self.inline))) + if index == 2: + return self.valobj.CreateValueFromExpression( + "explicit", str(int(self.explicit))) + if index == 3: + return self.valobj.CreateValueFromExpression( + "unicode", str(int(self.unicode))) + if index == 4: + return self.valobj.CreateValueFromExpression( + "special", str(int(self.special))) + if index == 5: + # we are handling the several possible combinations of flags. + # for each known combination we have a function that knows how to + # go fetch the data from memory instead of running code. if a string is not + # correctly displayed, one should start by finding a combination of flags that + # makes it different from these known cases, and provide a new reader function + # if this is not possible, a new flag might have to be made up (like the "special" flag + # below, which is not a real flag in CFString), or alternatively one might need to use + # the ObjC runtime helper to detect the new class and deal with it accordingly + # print 'mutable = ' + str(self.mutable) + # print 'inline = ' + str(self.inline) + # print 'explicit = ' + str(self.explicit) + # print 'unicode = ' + str(self.unicode) + # print 'special = ' + str(self.special) + if self.mutable: + return self.handle_mutable_string() + elif self.inline and self.explicit and \ + self.unicode == False and self.special == False and \ + self.mutable == False: + return self.handle_inline_explicit() + elif self.unicode: + return self.handle_unicode_string() + elif self.special: + return self.handle_special() + elif self.inline: + return self.handle_UTF8_inline() + else: + return self.handle_UTF8_not_inline() + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + logger >> "Querying for child ['" + str(name) + "']" + if name == "content": + return self.num_children() - 1 + if name == "mutable": + return 0 + if name == "inline": + return 1 + if name == "explicit": + return 2 + if name == "unicode": + return 3 + if name == "special": + return 4 + + # CFRuntimeBase is defined as having an additional + # 4 bytes (padding?) on LP64 architectures + # to get its size we add up sizeof(pointer)+4 + # and then add 4 more bytes if we are on a 64bit system + def size_of_cfruntime_base(self): + logger = lldb.formatters.Logger.Logger() + return self.pointer_size + 4 + (4 if self.is_64_bit else 0) + + # the info bits are part of the CFRuntimeBase structure + # to get at them we have to skip a uintptr_t and then get + # at the least-significant byte of a 4 byte array. If we are + # on big-endian this means going to byte 3, if we are on + # little endian (OSX & iOS), this means reading byte 0 + def offset_of_info_bits(self): + logger = lldb.formatters.Logger.Logger() + offset = self.pointer_size + if not self.is_little: + offset = offset + 3 + return offset + + def read_info_bits(self): + logger = lldb.formatters.Logger.Logger() + cfinfo = self.valobj.CreateChildAtOffset( + "cfinfo", + self.offset_of_info_bits(), + self.valobj.GetType().GetBasicType( + lldb.eBasicTypeChar)) + cfinfo.SetFormat(11) + info = cfinfo.GetValue() + if info is not None: + self.invalid = False + return int(info, 0) + else: + self.invalid = True + return None + + # calculating internal flag bits of the CFString object + # this stuff is defined and discussed in CFString.c + def is_mutable(self): + logger = lldb.formatters.Logger.Logger() + return (self.info_bits & 1) == 1 + + def is_inline(self): + logger = lldb.formatters.Logger.Logger() + return (self.info_bits & 0x60) == 0 + + # this flag's name is ambiguous, it turns out + # we must skip a length byte to get at the data + # when this flag is False + def has_explicit_length(self): + logger = lldb.formatters.Logger.Logger() + return (self.info_bits & (1 | 4)) != 4 + + # probably a subclass of NSString. obtained this from [str pathExtension] + # here info_bits = 0 and Unicode data at the start of the padding word + # in the long run using the isa value might be safer as a way to identify this + # instead of reading the info_bits + def is_special_case(self): + logger = lldb.formatters.Logger.Logger() + return self.info_bits == 0 + + def is_unicode(self): + logger = lldb.formatters.Logger.Logger() + return (self.info_bits & 0x10) == 0x10 + + # preparing ourselves to read into memory + # by adjusting architecture-specific info + def adjust_for_architecture(self): + logger = lldb.formatters.Logger.Logger() + self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize() + self.is_64_bit = self.pointer_size == 8 + self.is_little = self.valobj.GetTarget().GetProcess( + ).GetByteOrder() == lldb.eByteOrderLittle + + # reading info bits out of the CFString and computing + # useful values to get at the real data + def compute_flags(self): + logger = lldb.formatters.Logger.Logger() + self.info_bits = self.read_info_bits() + if self.info_bits is None: + return + self.mutable = self.is_mutable() + self.inline = self.is_inline() + self.explicit = self.has_explicit_length() + self.unicode = self.is_unicode() + self.special = self.is_special_case() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + self.compute_flags() diff --git a/examples/summaries/cocoa/Class.py b/examples/summaries/cocoa/Class.py new file mode 100644 index 000000000..1c97ed896 --- /dev/null +++ b/examples/summaries/cocoa/Class.py @@ -0,0 +1,22 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +import lldb +import lldb.runtime.objc.objc_runtime +import lldb.formatters.Logger + + +def Class_Summary(valobj, dict): + logger = lldb.formatters.Logger.Logger() + runtime = lldb.runtime.objc.objc_runtime.ObjCRuntime.runtime_from_isa( + valobj) + if runtime is None or not runtime.is_valid(): + return '' + class_data = runtime.read_class_data() + if class_data is None or not class_data.is_valid(): + return '' + return class_data.class_name() diff --git a/examples/summaries/cocoa/Logger.py b/examples/summaries/cocoa/Logger.py new file mode 100644 index 000000000..e518b75b2 --- /dev/null +++ b/examples/summaries/cocoa/Logger.py @@ -0,0 +1,133 @@ +from __future__ import print_function +import sys +import os.path +import inspect + + +class NopLogger: + + def __init__(self): + pass + + def write(self, data): + pass + + def flush(self): + pass + + def close(self): + pass + + +class StdoutLogger: + + def __init__(self): + pass + + def write(self, data): + print(data) + + def flush(self): + pass + + def close(self): + pass + + +class FileLogger: + + def __init__(self, name): + self.file = None + try: + name = os.path.abspath(name) + self.file = open(name, 'a') + except: + try: + self.file = open('formatters.log', 'a') + except: + pass + + def write(self, data): + if self.file is not None: + print(data, file=self.file) + else: + print(data) + + def flush(self): + if self.file is not None: + self.file.flush() + + def close(self): + if self.file is not None: + self.file.close() + self.file = None + +# to enable logging: +# define lldb.formatters.Logger._lldb_formatters_debug_level to any number greater than 0 +# if you define it to any value greater than 1, the log will be automatically flushed after each write (slower but should make sure most of the stuff makes it to the log even if we crash) +# if you define it to any value greater than 2, the calling function's details will automatically be logged (even slower, but provides additional details) +# if you need the log to go to a file instead of on screen, define +# lldb.formatters.Logger._lldb_formatters_debug_filename to a valid +# filename + + +class Logger: + + def __init__(self, autoflush=False, logcaller=False): + global _lldb_formatters_debug_level + global _lldb_formatters_debug_filename + self.autoflush = autoflush + want_log = False + try: + want_log = (_lldb_formatters_debug_level > 0) + except: + pass + if not (want_log): + self.impl = NopLogger() + return + want_file = False + try: + want_file = (_lldb_formatters_debug_filename is not None and _lldb_formatters_debug_filename != + '' and _lldb_formatters_debug_filename != 0) + except: + pass + if want_file: + self.impl = FileLogger(_lldb_formatters_debug_filename) + else: + self.impl = StdoutLogger() + try: + self.autoflush = (_lldb_formatters_debug_level > 1) + except: + self.autoflush = autoflush + want_caller_info = False + try: + want_caller_info = (_lldb_formatters_debug_level > 2) + except: + pass + if want_caller_info: + self._log_caller() + + def _log_caller(self): + caller = inspect.stack()[2] + try: + if caller is not None and len(caller) > 3: + self.write('Logging from function ' + str(caller)) + else: + self.write( + 'Caller info not available - Required caller logging not possible') + finally: + del caller # needed per Python docs to avoid keeping objects alive longer than we care + + def write(self, data): + self.impl.write(data) + if self.autoflush: + self.flush() + + def __rshift__(self, data): + self.write(data) + + def flush(self): + self.impl.flush() + + def close(self): + self.impl.close() diff --git a/examples/summaries/cocoa/NSBundle.py b/examples/summaries/cocoa/NSBundle.py new file mode 100644 index 000000000..298150e6c --- /dev/null +++ b/examples/summaries/cocoa/NSBundle.py @@ -0,0 +1,145 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSBundle +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import NSURL +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but a summary for an NSURL, so they need not +# obey the interface specification for synthetic children providers + + +class NSBundleKnown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSString): + self.sys_params.types_cache.NSString = self.valobj.GetTarget( + ).FindFirstType('NSString').GetPointerType() + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # we need to skip the ISA, plus four other values + # that are luckily each a pointer in size + # which makes our computation trivial :-) + def offset(self): + logger = lldb.formatters.Logger.Logger() + return 5 * self.sys_params.pointer_size + + def url_text(self): + logger = lldb.formatters.Logger.Logger() + global statistics + text = self.valobj.CreateChildAtOffset( + "text", self.offset(), self.sys_params.types_cache.NSString) + my_string = text.GetSummary() + if (my_string is None) or (my_string == ''): + statistics.metric_hit( + 'unknown_class', str( + self.valobj.GetName()) + " triggered unknown pointer location") + return NSBundleUnknown_SummaryProvider( + self.valobj, self.sys_params).url_text() + else: + statistics.metric_hit('code_notrun', self.valobj) + return my_string + + +class NSBundleUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def url_text(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + expr = "(NSString*)[" + stream.GetData() + " bundlePath]" + url_text_vo = self.valobj.CreateValueFromExpression("path", expr) + if url_text_vo.IsValid(): + return url_text_vo.GetSummary() + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSBundle': + wrapper = NSBundleKnown_SummaryProvider(valobj, class_data.sys_params) + # [NSBundle mainBundle] does return an object that is + # not correctly filled out for our purposes, so we still + # end up having to run code in that case + # statistics.metric_hit('code_notrun',valobj) + else: + wrapper = NSBundleUnknown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSBundle_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.url_text() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None or summary == '': + summary = '' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSBundle.NSBundle_SummaryProvider NSBundle") diff --git a/examples/summaries/cocoa/NSData.py b/examples/summaries/cocoa/NSData.py new file mode 100644 index 000000000..bf4f2c6bb --- /dev/null +++ b/examples/summaries/cocoa/NSData.py @@ -0,0 +1,182 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSData +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the length for an NSData, so they need not +# obey the interface specification for synthetic children providers + + +class NSConcreteData_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + logger >> "NSConcreteData_SummaryProvider __init__" + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + self.adjust_for_architecture() + + # one pointer is the ISA + # then there are 32 bit worth of flags and other data + # however, on 64bit systems these are padded to be a full + # machine word long, which means we actually have two pointers + # worth of data to skip + def offset(self): + return 2 * self.sys_params.pointer_size + + def length(self): + logger = lldb.formatters.Logger.Logger() + logger >> "NSConcreteData_SummaryProvider length" + size = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + logger >> str(size) + logger >> str(size.GetValueAsUnsigned(0)) + return size.GetValueAsUnsigned(0) + + +class NSDataUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + logger >> "NSDataUnknown_SummaryProvider __init__" + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + self.adjust_for_architecture() + + def length(self): + logger = lldb.formatters.Logger.Logger() + logger >> "NSDataUnknown_SummaryProvider length" + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + logger >> stream.GetData() + num_children_vo = self.valobj.CreateValueFromExpression( + "count", "(int)[" + stream.GetData() + " length]") + logger >> "still in after expression: " + str(num_children_vo) + if num_children_vo.IsValid(): + logger >> "wow - expr output is valid: " + \ + str(num_children_vo.GetValueAsUnsigned()) + return num_children_vo.GetValueAsUnsigned(0) + logger >> "invalid expr output - too bad" + return '' + + +def GetSummary_Impl(valobj): + global statistics + logger = lldb.formatters.Logger.Logger() + logger >> "NSData GetSummary_Impl" + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + logger >> "got a wrapper summary - using it" + return wrapper + + name_string = class_data.class_name() + logger >> "class name: " + name_string + if name_string == 'NSConcreteData' or \ + name_string == 'NSConcreteMutableData' or \ + name_string == '__NSCFData': + wrapper = NSConcreteData_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSDataUnknown_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSData_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + logger >> "NSData_SummaryProvider" + provider = GetSummary_Impl(valobj) + logger >> "found a summary provider, it is: " + str(provider) + if provider is not None: + try: + summary = provider.length() + except: + summary = None + logger >> "got a summary: it is " + str(summary) + if summary is None: + summary = '' + elif isinstance(summary, basestring): + pass + else: + if summary == 1: + summary = '1 byte' + else: + summary = str(summary) + ' bytes' + return summary + return 'Summary Unavailable' + + +def NSData_SummaryProvider2(valobj, dict): + logger = lldb.formatters.Logger.Logger() + logger >> "NSData_SummaryProvider2" + provider = GetSummary_Impl(valobj) + logger >> "found a summary provider, it is: " + str(provider) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.length() + except: + summary = None + logger >> "got a summary: it is " + str(summary) + if summary is None: + summary = '' + elif isinstance(summary, basestring): + pass + else: + if summary == 1: + summary = '@"1 byte"' + else: + summary = '@"' + str(summary) + ' bytes"' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSData.NSData_SummaryProvider NSData") + debugger.HandleCommand( + "type summary add -F NSData.NSData_SummaryProvider2 CFDataRef CFMutableDataRef") diff --git a/examples/summaries/cocoa/NSDate.py b/examples/summaries/cocoa/NSDate.py new file mode 100644 index 000000000..4efe76eca --- /dev/null +++ b/examples/summaries/cocoa/NSDate.py @@ -0,0 +1,307 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSDate +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import struct +import time +import datetime +import CFString +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# Python promises to start counting time at midnight on Jan 1st on the epoch year +# hence, all we need to know is the epoch year +python_epoch = time.gmtime(0).tm_year + +osx_epoch = datetime.date(2001, 1, 1).timetuple() + + +def mkgmtime(t): + logger = lldb.formatters.Logger.Logger() + return time.mktime(t) - time.timezone + +osx_epoch = mkgmtime(osx_epoch) + + +def osx_to_python_time(osx): + logger = lldb.formatters.Logger.Logger() + if python_epoch <= 2001: + return osx + osx_epoch + else: + return osx - osx_epoch + +# represent a struct_time as a string in the format used by Xcode + + +def xcode_format_time(X): + logger = lldb.formatters.Logger.Logger() + return time.strftime('%Y-%m-%d %H:%M:%S %Z', X) + +# represent a count-since-epoch as a string in the format used by Xcode + + +def xcode_format_count(X): + logger = lldb.formatters.Logger.Logger() + return xcode_format_time(time.localtime(X)) + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the summary for NSDate, so they need not +# obey the interface specification for synthetic children providers + + +class NSTaggedDate_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, info_bits, data, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + # NSDate is not using its info_bits for info like NSNumber is + # so we need to regroup info_bits and data + self.data = ((data << 8) | (info_bits << 4)) + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def value(self): + logger = lldb.formatters.Logger.Logger() + # the value of the date-time object is wrapped into the pointer value + # unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT + # while all Python knows about is the "epoch", which is a platform-dependent + # year (1970 of *nix) whose Jan 1 at midnight is taken as reference + value_double = struct.unpack('d', struct.pack('Q', self.data))[0] + if value_double == -63114076800.0: + return '0001-12-30 00:00:00 +0000' + return xcode_format_count(osx_to_python_time(value_double)) + + +class NSUntaggedDate_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.double): + self.sys_params.types_cache.double = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeDouble) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def value(self): + logger = lldb.formatters.Logger.Logger() + value = self.valobj.CreateChildAtOffset( + "value", self.offset(), self.sys_params.types_cache.double) + value_double = struct.unpack( + 'd', struct.pack( + 'Q', value.GetData().uint64[0]))[0] + if value_double == -63114076800.0: + return '0001-12-30 00:00:00 +0000' + return xcode_format_count(osx_to_python_time(value_double)) + + +class NSCalendarDate_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.double): + self.sys_params.types_cache.double = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeDouble) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def offset(self): + logger = lldb.formatters.Logger.Logger() + return 2 * self.sys_params.pointer_size + + def value(self): + logger = lldb.formatters.Logger.Logger() + value = self.valobj.CreateChildAtOffset( + "value", self.offset(), self.sys_params.types_cache.double) + value_double = struct.unpack( + 'd', struct.pack( + 'Q', value.GetData().uint64[0]))[0] + return xcode_format_count(osx_to_python_time(value_double)) + + +class NSTimeZoneClass_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.voidptr): + self.sys_params.types_cache.voidptr = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeVoid).GetPointerType() + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def timezone(self): + logger = lldb.formatters.Logger.Logger() + tz_string = self.valobj.CreateChildAtOffset( + "tz_name", self.offset(), self.sys_params.types_cache.voidptr) + return CFString.CFString_SummaryProvider(tz_string, None) + + +class NSUnknownDate_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def value(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + expr = "(NSString*)[" + stream.GetData() + " description]" + num_children_vo = self.valobj.CreateValueFromExpression("str", expr) + if num_children_vo.IsValid(): + return num_children_vo.GetSummary() + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate': + if class_data.is_tagged(): + wrapper = NSTaggedDate_SummaryProvider( + valobj, class_data.info_bits(), class_data.value(), class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSUntaggedDate_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == 'NSCalendarDate': + wrapper = NSCalendarDate_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == '__NSTimeZone': + wrapper = NSTimeZoneClass_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSUnknownDate_SummaryProvider(valobj) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSDate_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.value() + except: + summary = None + if summary is None: + summary = '' + return str(summary) + return 'Summary Unavailable' + + +def NSTimeZone_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.timezone() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + return str(summary) + return 'Summary Unavailable' + + +def CFAbsoluteTime_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + try: + value_double = struct.unpack( + 'd', struct.pack( + 'Q', valobj.GetData().uint64[0]))[0] + return xcode_format_count(osx_to_python_time(value_double)) + except: + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSDate.NSDate_SummaryProvider NSDate") + debugger.HandleCommand( + "type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime") + debugger.HandleCommand( + "type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef") diff --git a/examples/summaries/cocoa/NSException.py b/examples/summaries/cocoa/NSException.py new file mode 100644 index 000000000..826871d70 --- /dev/null +++ b/examples/summaries/cocoa/NSException.py @@ -0,0 +1,134 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# summary provider for class NSException +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import CFString +import lldb +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + + +class NSKnownException_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.id): + self.sys_params.types_cache.id = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeObjCID) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def offset_name(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def offset_reason(self): + logger = lldb.formatters.Logger.Logger() + return 2 * self.sys_params.pointer_size + + def description(self): + logger = lldb.formatters.Logger.Logger() + name_ptr = self.valobj.CreateChildAtOffset( + "name", self.offset_name(), self.sys_params.types_cache.id) + reason_ptr = self.valobj.CreateChildAtOffset( + "reason", self.offset_reason(), self.sys_params.types_cache.id) + return 'name:' + CFString.CFString_SummaryProvider( + name_ptr, None) + ' reason:' + CFString.CFString_SummaryProvider(reason_ptr, None) + + +class NSUnknownException_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def description(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + name_vo = self.valobj.CreateValueFromExpression( + "name", "(NSString*)[" + stream.GetData() + " name]") + reason_vo = self.valobj.CreateValueFromExpression( + "reason", "(NSString*)[" + stream.GetData() + " reason]") + if name_vo.IsValid() and reason_vo.IsValid(): + return CFString.CFString_SummaryProvider( + name_vo, None) + ' ' + CFString.CFString_SummaryProvider(reason_vo, None) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSException': + wrapper = NSKnownException_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSUnknownException_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSException_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.description() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + return str(summary) + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSException.NSException_SummaryProvider NSException") diff --git a/examples/summaries/cocoa/NSIndexSet.py b/examples/summaries/cocoa/NSIndexSet.py new file mode 100644 index 000000000..ca9906158 --- /dev/null +++ b/examples/summaries/cocoa/NSIndexSet.py @@ -0,0 +1,176 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NS(Mutable)IndexSet +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the count of values for an NSIndexSet, so they need not +# obey the interface specification for synthetic children providers + + +class NSIndexSetClass_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + self.sys_params.types_cache.uint32 = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.sys_params.types_cache.uint32 = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + if not(self.sys_params.types_cache.uint32): + self.sys_params.types_cache.uint32 = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range) + # the count is stored in the set itself, 3 pointers into it + # otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this + # additional structure will contain the count two pointers deep + # a bunch of flags allow us to detect an empty set, vs. a one-range set, + # vs. a multi-range set + def count(self): + logger = lldb.formatters.Logger.Logger() + mode_chooser_vo = self.valobj.CreateChildAtOffset( + "mode_chooser", + self.sys_params.pointer_size, + self.sys_params.types_cache.uint32) + mode_chooser = mode_chooser_vo.GetValueAsUnsigned(0) + if self.sys_params.is_64_bit: + mode_chooser = mode_chooser & 0x00000000FFFFFFFF + # empty set + if mode_chooser & 0x01 == 1: + return 0 + # single range + if mode_chooser & 0x02 == 2: + mode = 1 + # multi range + else: + mode = 2 + if mode == 1: + count_vo = self.valobj.CreateChildAtOffset( + "count", + 3 * self.sys_params.pointer_size, + self.sys_params.types_cache.NSUInteger) + else: + count_ptr = self.valobj.CreateChildAtOffset( + "count_ptr", + 2 * self.sys_params.pointer_size, + self.sys_params.types_cache.NSUInteger) + count_vo = self.valobj.CreateValueFromAddress( + "count", + count_ptr.GetValueAsUnsigned() + + 2 * + self.sys_params.pointer_size, + self.sys_params.types_cache.NSUInteger) + return count_vo.GetValueAsUnsigned(0) + + +class NSIndexSetUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def count(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + expr = "(int)[" + stream.GetData() + " count]" + num_children_vo = self.valobj.CreateValueFromExpression("count", expr) + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSIndexSet' or name_string == 'NSMutableIndexSet': + wrapper = NSIndexSetClass_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSIndexSetUnknown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSIndexSet_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.count() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + if isinstance(summary, basestring): + return summary + else: + summary = str(summary) + (' indexes' if summary != 1 else ' index') + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet") diff --git a/examples/summaries/cocoa/NSMachPort.py b/examples/summaries/cocoa/NSMachPort.py new file mode 100644 index 000000000..6eea6ca66 --- /dev/null +++ b/examples/summaries/cocoa/NSMachPort.py @@ -0,0 +1,141 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSMachPort +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the port number of an NSMachPort, so they need not +# obey the interface specification for synthetic children providers + + +class NSMachPortKnown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # one pointer is the ISA + # then we have one other internal pointer, plus + # 4 bytes worth of flags. hence, these values + def offset(self): + logger = lldb.formatters.Logger.Logger() + if self.sys_params.is_64_bit: + return 20 + else: + return 12 + + def port(self): + logger = lldb.formatters.Logger.Logger() + vport = self.valobj.CreateChildAtOffset( + "port", self.offset(), self.sys_params.types_cache.NSUInteger) + return vport.GetValueAsUnsigned(0) + + +class NSMachPortUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def port(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + num_children_vo = self.valobj.CreateValueFromExpression( + "port", "(int)[" + stream.GetData() + " machPort]") + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSMachPort': + wrapper = NSMachPortKnown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSMachPortUnknown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSMachPort_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.port() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + if isinstance(summary, basestring): + return summay + return 'mach port: ' + str(summary) + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSMachPort.NSMachPort_SummaryProvider NSMachPort") diff --git a/examples/summaries/cocoa/NSNotification.py b/examples/summaries/cocoa/NSNotification.py new file mode 100644 index 000000000..319d7561e --- /dev/null +++ b/examples/summaries/cocoa/NSNotification.py @@ -0,0 +1,126 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSNotification +# the real summary is now C++ code built into LLDB +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import CFString +import lldb +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + + +class NSConcreteNotification_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.id): + self.sys_params.types_cache.id = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeObjCID) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # skip the ISA and go to the name pointer + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def name(self): + logger = lldb.formatters.Logger.Logger() + string_ptr = self.valobj.CreateChildAtOffset( + "name", self.offset(), self.sys_params.types_cache.id) + return CFString.CFString_SummaryProvider(string_ptr, None) + + +class NSNotificationUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def name(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + name_vo = self.valobj.CreateValueFromExpression( + "name", "(NSString*)[" + stream.GetData() + " name]") + if name_vo.IsValid(): + return CFString.CFString_SummaryProvider(name_vo, None) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSConcreteNotification': + wrapper = NSConcreteNotification_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSNotificationUnknown_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSNotification_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.name() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + return str(summary) + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSNotification.NSNotification_SummaryProvider NSNotification") diff --git a/examples/summaries/cocoa/NSNumber.py b/examples/summaries/cocoa/NSNumber.py new file mode 100644 index 000000000..3225ea95d --- /dev/null +++ b/examples/summaries/cocoa/NSNumber.py @@ -0,0 +1,269 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSNumber +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import struct +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the port number of an NSNumber, so they need not +# obey the interface specification for synthetic children providers + + +class NSTaggedNumber_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, info_bits, data, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.info_bits = info_bits + self.data = data + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def value(self): + logger = lldb.formatters.Logger.Logger() + # in spite of the plenty of types made available by the public NSNumber API + # only a bunch of these are actually used in the internal implementation + # unfortunately, the original type information appears to be lost + # so we try to at least recover the proper magnitude of the data + if self.info_bits == 0: + return '(char)' + \ + str(ord(ctypes.c_char(chr(self.data % 256)).value)) + if self.info_bits == 4: + return '(short)' + \ + str(ctypes.c_short(self.data % (256 * 256)).value) + if self.info_bits == 8: + return '(int)' + str(ctypes.c_int(self.data % + (256 * 256 * 256 * 256)).value) + if self.info_bits == 12: + return '(long)' + str(ctypes.c_long(self.data).value) + else: + return 'unexpected value:(info=' + str(self.info_bits) + \ + ", value = " + str(self.data) + ')' + + +class NSUntaggedNumber_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.char): + self.sys_params.types_cache.char = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeChar) + if not(self.sys_params.types_cache.short): + self.sys_params.types_cache.short = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeShort) + if not(self.sys_params.types_cache.ushort): + self.sys_params.types_cache.ushort = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedShort) + if not(self.sys_params.types_cache.int): + self.sys_params.types_cache.int = self.valobj.GetType().GetBasicType(lldb.eBasicTypeInt) + if not(self.sys_params.types_cache.long): + self.sys_params.types_cache.long = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeLong) + if not(self.sys_params.types_cache.ulong): + self.sys_params.types_cache.ulong = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + if not(self.sys_params.types_cache.longlong): + self.sys_params.types_cache.longlong = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeLongLong) + if not(self.sys_params.types_cache.ulonglong): + self.sys_params.types_cache.ulonglong = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLongLong) + if not(self.sys_params.types_cache.float): + self.sys_params.types_cache.float = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeFloat) + if not(self.sys_params.types_cache.double): + self.sys_params.types_cache.double = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeDouble) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def value(self): + logger = lldb.formatters.Logger.Logger() + global statistics + # we need to skip the ISA, then the next byte tells us what to read + # we then skip one other full pointer worth of data and then fetch the contents + # if we are fetching an int64 value, one more pointer must be skipped + # to get at our data + data_type_vo = self.valobj.CreateChildAtOffset( + "dt", self.sys_params.pointer_size, self.sys_params.types_cache.char) + data_type = ((data_type_vo.GetValueAsUnsigned(0) % 256) & 0x1F) + data_offset = 2 * self.sys_params.pointer_size + if data_type == 0B00001: + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.char) + statistics.metric_hit('code_notrun', self.valobj) + return '(char)' + \ + str(ord(ctypes.c_char(chr(data_vo.GetValueAsUnsigned(0))).value)) + elif data_type == 0B0010: + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.short) + statistics.metric_hit('code_notrun', self.valobj) + return '(short)' + str( + ctypes.c_short( + data_vo.GetValueAsUnsigned(0) % + (256 * 256)).value) + # IF tagged pointers are possible on 32bit+v2 runtime + # (of which the only existing instance should be iOS) + # then values of this type might be tagged + elif data_type == 0B0011: + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.int) + statistics.metric_hit('code_notrun', self.valobj) + return '(int)' + str(ctypes.c_int(data_vo.GetValueAsUnsigned(0) % + (256 * 256 * 256 * 256)).value) + # apparently, on is_64_bit architectures, these are the only values that will ever + # be represented by a non tagged pointers + elif data_type == 0B10001: + data_offset = data_offset + 8 # 8 is needed even if we are on 32bit + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.longlong) + statistics.metric_hit('code_notrun', self.valobj) + return '(long)' + \ + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value) + elif data_type == 0B0100: + if self.sys_params.is_64_bit: + data_offset = data_offset + self.sys_params.pointer_size + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.longlong) + statistics.metric_hit('code_notrun', self.valobj) + return '(long)' + \ + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value) + elif data_type == 0B0101: + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.longlong) + data_plain = int( + str(data_vo.GetValueAsUnsigned(0) & 0x00000000FFFFFFFF)) + packed = struct.pack('I', data_plain) + data_float = struct.unpack('f', packed)[0] + statistics.metric_hit('code_notrun', self.valobj) + return '(float)' + str(data_float) + elif data_type == 0B0110: + data_vo = self.valobj.CreateChildAtOffset( + "data", data_offset, self.sys_params.types_cache.longlong) + data_plain = data_vo.GetValueAsUnsigned(0) + data_double = struct.unpack('d', struct.pack('Q', data_plain))[0] + statistics.metric_hit('code_notrun', self.valobj) + return '(double)' + str(data_double) + statistics.metric_hit( + 'unknown_class', str( + valobj.GetName()) + " had unknown data_type " + str(data_type)) + return 'unexpected: dt = ' + str(data_type) + + +class NSUnknownNumber_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def value(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + expr = "(NSString*)[" + stream.GetData() + " stringValue]" + num_children_vo = self.valobj.CreateValueFromExpression("str", expr) + if num_children_vo.IsValid(): + return num_children_vo.GetSummary() + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSNumber' or name_string == '__NSCFNumber': + if class_data.is_tagged(): + wrapper = NSTaggedNumber_SummaryProvider( + valobj, class_data.info_bits(), class_data.value(), class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + # the wrapper might be unable to decipher what is into the NSNumber + # and then have to run code on it + wrapper = NSUntaggedNumber_SummaryProvider( + valobj, class_data.sys_params) + else: + wrapper = NSUnknownNumber_SummaryProvider( + valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSNumber_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.value() + except Exception as foo: + print foo +# except: + summary = None + logger >> "got summary " + str(summary) + if summary is None: + summary = '' + return str(summary) + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSNumber.NSNumber_SummaryProvider NSNumber") + debugger.HandleCommand( + "type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFBoolean") + debugger.HandleCommand( + "type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFNumber") diff --git a/examples/summaries/cocoa/NSSet.py b/examples/summaries/cocoa/NSSet.py new file mode 100644 index 000000000..a6c776867 --- /dev/null +++ b/examples/summaries/cocoa/NSSet.py @@ -0,0 +1,289 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# summary provider for NSSet +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import CFBag +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but the port number of an NSMachPort, so they need not +# obey the interface specification for synthetic children providers + + +class NSCFSet_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # one pointer is the ISA + # then we have one other internal pointer, plus + # 4 bytes worth of flags. hence, these values + def offset(self): + logger = lldb.formatters.Logger.Logger() + if self.sys_params.is_64_bit: + return 20 + else: + return 12 + + def count(self): + logger = lldb.formatters.Logger.Logger() + vcount = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + return vcount.GetValueAsUnsigned(0) + + +class NSSetUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def count(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + expr = "(int)[" + stream.GetData() + " count]" + num_children_vo = self.valobj.CreateValueFromExpression("count", expr) + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return '' + + +class NSSetI_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # we just need to skip the ISA and the count immediately follows + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def count(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + value = num_children_vo.GetValueAsUnsigned(0) + if value is not None: + # the MSB on immutable sets seems to be taken by some other data + # not sure if it is a bug or some weird sort of feature, but masking it out + # gets the count right (unless, of course, someone's dictionaries grow + # too large - but I have not tested this) + if self.sys_params.is_64_bit: + value = value & ~0xFF00000000000000 + else: + value = value & ~0xFF000000 + return value + + +class NSSetM_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSUInteger): + if self.sys_params.is_64_bit: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + else: + self.sys_params.types_cache.NSUInteger = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # we just need to skip the ISA and the count immediately follows + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def count(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset( + "count", self.offset(), self.sys_params.types_cache.NSUInteger) + return num_children_vo.GetValueAsUnsigned(0) + + +class NSCountedSet_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not (self.sys_params.types_cache.voidptr): + self.sys_params.types_cache.voidptr = self.valobj.GetType( + ).GetBasicType(lldb.eBasicTypeVoid).GetPointerType() + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # an NSCountedSet is implemented using a CFBag whose pointer just follows + # the ISA + def offset(self): + logger = lldb.formatters.Logger.Logger() + return self.sys_params.pointer_size + + def count(self): + logger = lldb.formatters.Logger.Logger() + cfbag_vo = self.valobj.CreateChildAtOffset( + "bag_impl", self.offset(), self.sys_params.types_cache.voidptr) + return CFBag.CFBagRef_SummaryProvider( + cfbag_vo, self.sys_params).length() + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == '__NSCFSet': + wrapper = NSCFSet_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == '__NSSetI': + wrapper = NSSetI_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == '__NSSetM': + wrapper = NSSetM_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + elif name_string == 'NSCountedSet': + wrapper = NSCountedSet_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSSetUnknown_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSSet_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + try: + summary = provider.count() + except: + summary = None + if summary is None: + summary = '' + if isinstance(summary, basestring): + return summary + else: + summary = str(summary) + \ + (' objects' if summary != 1 else ' object') + return summary + return 'Summary Unavailable' + + +def NSSet_SummaryProvider2(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.count() + except: + summary = None + logger >> "got summary " + str(summary) + # for some reason, one needs to clear some bits for the count returned + # to be correct when using directly CF*SetRef as compared to NS*Set + # this only happens on 64bit, and the bit mask was derived through + # experimentation (if counts start looking weird, then most probably + # the mask needs to be changed) + if summary is None: + summary = '' + if isinstance(summary, basestring): + return summary + else: + if provider.sys_params.is_64_bit: + summary = summary & ~0x1fff000000000000 + summary = '@"' + str(summary) + \ + (' values"' if summary != 1 else ' value"') + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSSet.NSSet_SummaryProvider NSSet") + debugger.HandleCommand( + "type summary add -F NSSet.NSSet_SummaryProvider2 CFSetRef CFMutableSetRef") diff --git a/examples/summaries/cocoa/NSURL.py b/examples/summaries/cocoa/NSURL.py new file mode 100644 index 000000000..ad28849a4 --- /dev/null +++ b/examples/summaries/cocoa/NSURL.py @@ -0,0 +1,153 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# summary provider for NSURL +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import CFString +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# despite the similary to synthetic children providers, these classes are not +# trying to provide anything but a summary for an NSURL, so they need not +# obey the interface specification for synthetic children providers + + +class NSURLKnown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + if not(self.sys_params.types_cache.NSString): + self.sys_params.types_cache.NSString = self.valobj.GetTarget( + ).FindFirstType('NSString').GetPointerType() + if not(self.sys_params.types_cache.NSURL): + self.sys_params.types_cache.NSURL = self.valobj.GetTarget( + ).FindFirstType('NSURL').GetPointerType() + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + # one pointer is the ISA + # then there is one more pointer and 8 bytes of plain data + # (which are also present on a 32-bit system) + # then there is a pointer to an NSString which is the url text + # optionally, the next pointer is another NSURL which is the "base" + # of this one when doing NSURLs composition (incidentally, NSURLs can + # recurse the base+text mechanism to any desired depth) + def offset_text(self): + logger = lldb.formatters.Logger.Logger() + return 24 if self.sys_params.is_64_bit else 16 + + def offset_base(self): + logger = lldb.formatters.Logger.Logger() + return self.offset_text() + self.sys_params.pointer_size + + def url_text(self): + logger = lldb.formatters.Logger.Logger() + text = self.valobj.CreateChildAtOffset( + "text", self.offset_text(), self.sys_params.types_cache.NSString) + base = self.valobj.CreateChildAtOffset( + "base", self.offset_base(), self.sys_params.types_cache.NSURL) + my_string = CFString.CFString_SummaryProvider(text, None) + if len(my_string) > 0 and base.GetValueAsUnsigned(0) != 0: + # remove final " from myself + my_string = my_string[0:len(my_string) - 1] + my_string = my_string + ' -- ' + my_base_string = NSURL_SummaryProvider(base, None) + if len(my_base_string) > 2: + # remove @" marker from base URL string + my_base_string = my_base_string[2:] + my_string = my_string + my_base_string + return my_string + + +class NSURLUnknown_SummaryProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.sys_params = params + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture() + + def url_text(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + url_text_vo = self.valobj.CreateValueFromExpression( + "url", "(NSString*)[" + stream.GetData() + " description]") + if url_text_vo.IsValid(): + return CFString.CFString_SummaryProvider(url_text_vo, None) + return '' + + +def GetSummary_Impl(valobj): + logger = lldb.formatters.Logger.Logger() + global statistics + class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( + valobj, statistics) + if wrapper: + return wrapper + + name_string = class_data.class_name() + logger >> "class name is: " + str(name_string) + + if name_string == 'NSURL': + wrapper = NSURLKnown_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit('code_notrun', valobj) + else: + wrapper = NSURLUnknown_SummaryProvider(valobj, class_data.sys_params) + statistics.metric_hit( + 'unknown_class', + valobj.GetName() + + " seen as " + + name_string) + return wrapper + + +def NSURL_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + provider = GetSummary_Impl(valobj) + if provider is not None: + if isinstance( + provider, + lldb.runtime.objc.objc_runtime.SpecialSituation_Description): + return provider.message() + try: + summary = provider.url_text() + except: + summary = None + logger >> "got summary " + str(summary) + if summary is None or summary == '': + summary = '' + return summary + return 'Summary Unavailable' + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + "type summary add -F NSURL.NSURL_SummaryProvider NSURL CFURLRef") diff --git a/examples/summaries/cocoa/Selector.py b/examples/summaries/cocoa/Selector.py new file mode 100644 index 000000000..05a196065 --- /dev/null +++ b/examples/summaries/cocoa/Selector.py @@ -0,0 +1,19 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +import lldb + + +def SEL_Summary(valobj, dict): + return valobj.Cast(valobj.GetType().GetBasicType( + lldb.eBasicTypeChar).GetPointerType()).GetSummary() + + +def SELPointer_Summary(valobj, dict): + return valobj.CreateValueFromAddress( + 'text', valobj.GetValueAsUnsigned(0), valobj.GetType().GetBasicType( + lldb.eBasicTypeChar)).AddressOf().GetSummary() diff --git a/examples/summaries/cocoa/attrib_fromdict.py b/examples/summaries/cocoa/attrib_fromdict.py new file mode 100644 index 000000000..39abe6bda --- /dev/null +++ b/examples/summaries/cocoa/attrib_fromdict.py @@ -0,0 +1,42 @@ +""" +Objective-C runtime wrapper for use by LLDB Python formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" + + +class AttributesDictionary: + + def __init__(self, allow_reset=True): + # need to do it this way to prevent endless recursion + self.__dict__['_dictionary'] = {} + self.__dict__['_allow_reset'] = allow_reset + + def __getattr__(self, name): + if not self._check_exists(name): + return None + value = self._dictionary[name] + return value + + def _set_impl(self, name, value): + self._dictionary[name] = value + + def _check_exists(self, name): + return name in self._dictionary + + def __setattr__(self, name, value): + if self._allow_reset: + self._set_impl(name, value) + else: + self.set_if_necessary(name, value) + + def set_if_necessary(self, name, value): + if not self._check_exists(name): + self._set_impl(name, value) + return True + return False + + def __len__(self): + return len(self._dictionary) diff --git a/examples/summaries/cocoa/cache.py b/examples/summaries/cocoa/cache.py new file mode 100644 index 000000000..63915cc66 --- /dev/null +++ b/examples/summaries/cocoa/cache.py @@ -0,0 +1,36 @@ +""" +Objective-C runtime wrapper for use by LLDB Python formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +import lldb.formatters.metrics + + +class Cache: + + def __init__(self): + self.data = {} + self.statistics = lldb.formatters.metrics.Metrics() + self.statistics.add_metric('hit') + self.statistics.add_metric('miss') + + def look_for_key(self, key): + if key in self.data: + return True + return False + + def add_item(self, key, value, ok_to_replace=True): + if not(ok_to_replace) and self.look_for_key(key): + return False + self.data[key] = value + return True + + def get_value(self, key, default=None): + if self.look_for_key(key): + self.statistics.metric_hit('hit', key) + return self.data[key] + else: + self.statistics.metric_hit('miss', key) + return default diff --git a/examples/summaries/cocoa/metrics.py b/examples/summaries/cocoa/metrics.py new file mode 100644 index 000000000..6a73a7344 --- /dev/null +++ b/examples/summaries/cocoa/metrics.py @@ -0,0 +1,112 @@ +""" +Objective-C runtime wrapper for use by LLDB Python formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +import lldb +import time +import datetime +import inspect + + +class TimeMetrics: + + @staticmethod + def generate(label=None): + return TimeMetrics(label) + + def __init__(self, lbl=None): + self.label = "" if lbl is None else lbl + pass + + def __enter__(self): + caller = inspect.stack()[1] + self.function = str(caller) + self.enter_time = time.clock() + + def __exit__(self, a, b, c): + self.exit_time = time.clock() + print("It took " + str(self.exit_time - self.enter_time) + + " time units to run through " + self.function + self.label) + return False + + +class Counter: + + def __init__(self): + self.count = 0 + self.list = [] + + def update(self, name): + self.count = self.count + 1 + # avoid getting the full dump of this ValueObject just to save its + # metrics + if isinstance(name, lldb.SBValue): + self.list.append(name.GetName()) + else: + self.list.append(str(name)) + + def __str__(self): + return str(self.count) + " times, for items [" + str(self.list) + "]" + + +class MetricsPrinter_Verbose: + + def __init__(self, metrics): + self.metrics = metrics + + def __str__(self): + string = "" + for key, value in self.metrics.metrics.items(): + string = string + "metric " + str(key) + ": " + str(value) + "\n" + return string + + +class MetricsPrinter_Compact: + + def __init__(self, metrics): + self.metrics = metrics + + def __str__(self): + string = "" + for key, value in self.metrics.metrics.items(): + string = string + "metric " + \ + str(key) + " was hit " + str(value.count) + " times\n" + return string + + +class Metrics: + + def __init__(self): + self.metrics = {} + + def add_metric(self, name): + self.metrics[name] = Counter() + + def metric_hit(self, metric, trigger): + self.metrics[metric].update(trigger) + + def __getitem__(self, key): + return self.metrics[key] + + def __getattr__(self, name): + if name == 'compact': + return MetricsPrinter_Compact(self) + if name == 'verbose': + return MetricsPrinter_Verbose(self) + raise AttributeError("%r object has no attribute %r" % + (type(self).__name__, name)) + + def __str__(self): + return str(self.verbose) + + def metric_success(self, metric): + total_count = 0 + metric_count = self[metric].count + for key, value in self.metrics.items(): + total_count = total_count + value.count + if total_count > 0: + return metric_count / float(total_count) + return 0 diff --git a/examples/summaries/cocoa/objc_runtime.py b/examples/summaries/cocoa/objc_runtime.py new file mode 100644 index 000000000..14ef1b42b --- /dev/null +++ b/examples/summaries/cocoa/objc_runtime.py @@ -0,0 +1,901 @@ +""" +Objective-C runtime wrapper for use by LLDB Python formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +import lldb +import lldb.formatters.cache +import lldb.formatters.attrib_fromdict +import functools +import lldb.formatters.Logger + + +class Utilities: + + @staticmethod + def read_ascii(process, pointer, max_len=128): + logger = lldb.formatters.Logger.Logger() + error = lldb.SBError() + content = None + try: + content = process.ReadCStringFromMemory(pointer, max_len, error) + except: + pass + if content is None or len(content) == 0 or error.fail: + return None + return content + + @staticmethod + def is_valid_pointer(pointer, pointer_size, allow_tagged=0, allow_NULL=0): + logger = lldb.formatters.Logger.Logger() + if pointer is None: + return 0 + if pointer == 0: + return allow_NULL + if allow_tagged and (pointer % 2) == 1: + return 1 + return ((pointer % pointer_size) == 0) + + # Objective-C runtime has a rule that pointers in a class_t will only have bits 0 thru 46 set + # so if any pointer has bits 47 thru 63 high we know that this is not a + # valid isa + @staticmethod + def is_allowed_pointer(pointer): + logger = lldb.formatters.Logger.Logger() + if pointer is None: + return 0 + return ((pointer & 0xFFFF800000000000) == 0) + + @staticmethod + def read_child_of(valobj, offset, type): + logger = lldb.formatters.Logger.Logger() + if offset == 0 and type.GetByteSize() == valobj.GetByteSize(): + return valobj.GetValueAsUnsigned() + child = valobj.CreateChildAtOffset("childUNK", offset, type) + if child is None or child.IsValid() == 0: + return None + return child.GetValueAsUnsigned() + + @staticmethod + def is_valid_identifier(name): + logger = lldb.formatters.Logger.Logger() + if name is None: + return None + if len(name) == 0: + return None + # technically, the ObjC runtime does not enforce any rules about what name a class can have + # in practice, the commonly used byte values for a class name are the letters, digits and some + # symbols: $, %, -, _, . + # WARNING: this means that you cannot use this runtime implementation if you need to deal + # with class names that use anything but what is allowed here + ok_values = dict.fromkeys( + "$%_.-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890") + return all(c in ok_values for c in name) + + @staticmethod + def check_is_osx_lion(target): + logger = lldb.formatters.Logger.Logger() + # assume the only thing that has a Foundation.framework is a Mac + # assume anything < Lion does not even exist + try: + mod = target.module['Foundation'] + except: + mod = None + if mod is None or mod.IsValid() == 0: + return None + ver = mod.GetVersion() + if ver is None or ver == []: + return None + return (ver[0] < 900) + + # a utility method that factors out code common to almost all the formatters + # takes in an SBValue and a metrics object + # returns a class_data and a wrapper (or None, if the runtime alone can't + # decide on a wrapper) + @staticmethod + def prepare_class_detection(valobj, statistics): + logger = lldb.formatters.Logger.Logger() + class_data = ObjCRuntime(valobj) + if class_data.is_valid() == 0: + statistics.metric_hit('invalid_pointer', valobj) + wrapper = InvalidPointer_Description( + valobj.GetValueAsUnsigned(0) == 0) + return class_data, wrapper + class_data = class_data.read_class_data() + if class_data.is_valid() == 0: + statistics.metric_hit('invalid_isa', valobj) + wrapper = InvalidISA_Description() + return class_data, wrapper + if class_data.is_kvo(): + class_data = class_data.get_superclass() + if class_data.class_name() == '_NSZombie_OriginalClass': + wrapper = ThisIsZombie_Description() + return class_data, wrapper + return class_data, None + + +class RoT_Data: + + def __init__(self, rot_pointer, params): + logger = lldb.formatters.Logger.Logger() + if (Utilities.is_valid_pointer(rot_pointer.GetValueAsUnsigned(), + params.pointer_size, allow_tagged=0)): + self.sys_params = params + self.valobj = rot_pointer + #self.flags = Utilities.read_child_of(self.valobj,0,self.sys_params.uint32_t) + #self.instanceStart = Utilities.read_child_of(self.valobj,4,self.sys_params.uint32_t) + self.instanceSize = None # lazy fetching + offset = 24 if self.sys_params.is_64_bit else 16 + #self.ivarLayoutPtr = Utilities.read_child_of(self.valobj,offset,self.sys_params.addr_ptr_type) + self.namePointer = Utilities.read_child_of( + self.valobj, offset, self.sys_params.types_cache.addr_ptr_type) + self.valid = 1 # self.check_valid() + else: + logger >> "Marking as invalid - rot is invalid" + self.valid = 0 + if self.valid: + self.name = Utilities.read_ascii( + self.valobj.GetTarget().GetProcess(), self.namePointer) + if not(Utilities.is_valid_identifier(self.name)): + logger >> "Marking as invalid - name is invalid" + self.valid = 0 + + # perform sanity checks on the contents of this class_ro_t + def check_valid(self): + self.valid = 1 + # misaligned pointers seem to be possible for this field + # if not(Utilities.is_valid_pointer(self.namePointer,self.sys_params.pointer_size,allow_tagged=0)): + # self.valid = 0 + # pass + + def __str__(self): + logger = lldb.formatters.Logger.Logger() + return \ + "instanceSize = " + hex(self.instance_size()) + "\n" + \ + "namePointer = " + hex(self.namePointer) + " --> " + self.name + + def is_valid(self): + return self.valid + + def instance_size(self, align=0): + logger = lldb.formatters.Logger.Logger() + if self.is_valid() == 0: + return None + if self.instanceSize is None: + self.instanceSize = Utilities.read_child_of( + self.valobj, 8, self.sys_params.types_cache.uint32_t) + if align: + unalign = self.instance_size(0) + if self.sys_params.is_64_bit: + return ((unalign + 7) & ~7) % 0x100000000 + else: + return ((unalign + 3) & ~3) % 0x100000000 + else: + return self.instanceSize + + +class RwT_Data: + + def __init__(self, rwt_pointer, params): + logger = lldb.formatters.Logger.Logger() + if (Utilities.is_valid_pointer(rwt_pointer.GetValueAsUnsigned(), + params.pointer_size, allow_tagged=0)): + self.sys_params = params + self.valobj = rwt_pointer + #self.flags = Utilities.read_child_of(self.valobj,0,self.sys_params.uint32_t) + #self.version = Utilities.read_child_of(self.valobj,4,self.sys_params.uint32_t) + self.roPointer = Utilities.read_child_of( + self.valobj, 8, self.sys_params.types_cache.addr_ptr_type) + self.check_valid() + else: + logger >> "Marking as invalid - rwt is invald" + self.valid = 0 + if self.valid: + self.rot = self.valobj.CreateValueFromData( + "rot", lldb.SBData.CreateDataFromUInt64Array( + self.sys_params.endianness, self.sys_params.pointer_size, [ + self.roPointer]), self.sys_params.types_cache.addr_ptr_type) +# self.rot = self.valobj.CreateValueFromAddress("rot",self.roPointer,self.sys_params.types_cache.addr_ptr_type).AddressOf() + self.data = RoT_Data(self.rot, self.sys_params) + + # perform sanity checks on the contents of this class_rw_t + def check_valid(self): + logger = lldb.formatters.Logger.Logger() + self.valid = 1 + if not( + Utilities.is_valid_pointer( + self.roPointer, + self.sys_params.pointer_size, + allow_tagged=0)): + logger >> "Marking as invalid - ropointer is invalid" + self.valid = 0 + + def __str__(self): + logger = lldb.formatters.Logger.Logger() + return \ + "roPointer = " + hex(self.roPointer) + + def is_valid(self): + logger = lldb.formatters.Logger.Logger() + if self.valid: + return self.data.is_valid() + return 0 + + +class Class_Data_V2: + + def __init__(self, isa_pointer, params): + logger = lldb.formatters.Logger.Logger() + if (isa_pointer is not None) and (Utilities.is_valid_pointer( + isa_pointer.GetValueAsUnsigned(), params.pointer_size, allow_tagged=0)): + self.sys_params = params + self.valobj = isa_pointer + self.check_valid() + else: + logger >> "Marking as invalid - isa is invalid or None" + self.valid = 0 + if self.valid: + self.rwt = self.valobj.CreateValueFromData( + "rwt", lldb.SBData.CreateDataFromUInt64Array( + self.sys_params.endianness, self.sys_params.pointer_size, [ + self.dataPointer]), self.sys_params.types_cache.addr_ptr_type) +# self.rwt = self.valobj.CreateValueFromAddress("rwt",self.dataPointer,self.sys_params.types_cache.addr_ptr_type).AddressOf() + self.data = RwT_Data(self.rwt, self.sys_params) + + # perform sanity checks on the contents of this class_t + # this call tries to minimize the amount of data fetched- as soon as we have "proven" + # that we have an invalid object, we stop reading + def check_valid(self): + logger = lldb.formatters.Logger.Logger() + self.valid = 1 + + self.isaPointer = Utilities.read_child_of( + self.valobj, 0, self.sys_params.types_cache.addr_ptr_type) + if not( + Utilities.is_valid_pointer( + self.isaPointer, + self.sys_params.pointer_size, + allow_tagged=0)): + logger >> "Marking as invalid - isaPointer is invalid" + self.valid = 0 + return + if not(Utilities.is_allowed_pointer(self.isaPointer)): + logger >> "Marking as invalid - isaPointer is not allowed" + self.valid = 0 + return + + self.cachePointer = Utilities.read_child_of( + self.valobj, + 2 * self.sys_params.pointer_size, + self.sys_params.types_cache.addr_ptr_type) + if not( + Utilities.is_valid_pointer( + self.cachePointer, + self.sys_params.pointer_size, + allow_tagged=0)): + logger >> "Marking as invalid - cachePointer is invalid" + self.valid = 0 + return + if not(Utilities.is_allowed_pointer(self.cachePointer)): + logger >> "Marking as invalid - cachePointer is not allowed" + self.valid = 0 + return + self.dataPointer = Utilities.read_child_of( + self.valobj, + 4 * self.sys_params.pointer_size, + self.sys_params.types_cache.addr_ptr_type) + if not( + Utilities.is_valid_pointer( + self.dataPointer, + self.sys_params.pointer_size, + allow_tagged=0)): + logger >> "Marking as invalid - dataPointer is invalid" + self.valid = 0 + return + if not(Utilities.is_allowed_pointer(self.dataPointer)): + logger >> "Marking as invalid - dataPointer is not allowed" + self.valid = 0 + return + + self.superclassIsaPointer = Utilities.read_child_of( + self.valobj, + 1 * self.sys_params.pointer_size, + self.sys_params.types_cache.addr_ptr_type) + if not( + Utilities.is_valid_pointer( + self.superclassIsaPointer, + self.sys_params.pointer_size, + allow_tagged=0, + allow_NULL=1)): + logger >> "Marking as invalid - superclassIsa is invalid" + self.valid = 0 + return + if not(Utilities.is_allowed_pointer(self.superclassIsaPointer)): + logger >> "Marking as invalid - superclassIsa is not allowed" + self.valid = 0 + return + + # in general, KVO is implemented by transparently subclassing + # however, there could be exceptions where a class does something else + # internally to implement the feature - this method will have no clue that a class + # has been KVO'ed unless the standard implementation technique is used + def is_kvo(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + if self.class_name().startswith("NSKVONotifying_"): + return 1 + return 0 + + # some CF classes have a valid ObjC isa in their CFRuntimeBase + # but instead of being class-specific this isa points to a match-'em-all class + # which is __NSCFType (the versions without __ also exists and we are matching to it + # just to be on the safe side) + def is_cftype(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + return self.class_name() == '__NSCFType' or self.class_name() == 'NSCFType' + + def get_superclass(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + parent_isa_pointer = self.valobj.CreateChildAtOffset( + "parent_isa", self.sys_params.pointer_size, self.sys_params.addr_ptr_type) + return Class_Data_V2(parent_isa_pointer, self.sys_params) + else: + return None + + def class_name(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + return self.data.data.name + else: + return None + + def is_valid(self): + logger = lldb.formatters.Logger.Logger() + if self.valid: + return self.data.is_valid() + return 0 + + def __str__(self): + logger = lldb.formatters.Logger.Logger() + return 'isaPointer = ' + hex(self.isaPointer) + "\n" + \ + "superclassIsaPointer = " + hex(self.superclassIsaPointer) + "\n" + \ + "cachePointer = " + hex(self.cachePointer) + "\n" + \ + "data = " + hex(self.dataPointer) + + def is_tagged(self): + return 0 + + def instance_size(self, align=0): + logger = lldb.formatters.Logger.Logger() + if self.is_valid() == 0: + return None + return self.rwt.rot.instance_size(align) + +# runtime v1 is much less intricate than v2 and stores relevant +# information directly in the class_t object + + +class Class_Data_V1: + + def __init__(self, isa_pointer, params): + logger = lldb.formatters.Logger.Logger() + if (isa_pointer is not None) and (Utilities.is_valid_pointer( + isa_pointer.GetValueAsUnsigned(), params.pointer_size, allow_tagged=0)): + self.valid = 1 + self.sys_params = params + self.valobj = isa_pointer + self.check_valid() + else: + logger >> "Marking as invalid - isaPointer is invalid or None" + self.valid = 0 + if self.valid: + self.name = Utilities.read_ascii( + self.valobj.GetTarget().GetProcess(), self.namePointer) + if not(Utilities.is_valid_identifier(self.name)): + logger >> "Marking as invalid - name is not valid" + self.valid = 0 + + # perform sanity checks on the contents of this class_t + def check_valid(self): + logger = lldb.formatters.Logger.Logger() + self.valid = 1 + + self.isaPointer = Utilities.read_child_of( + self.valobj, 0, self.sys_params.types_cache.addr_ptr_type) + if not( + Utilities.is_valid_pointer( + self.isaPointer, + self.sys_params.pointer_size, + allow_tagged=0)): + logger >> "Marking as invalid - isaPointer is invalid" + self.valid = 0 + return + + self.superclassIsaPointer = Utilities.read_child_of( + self.valobj, + 1 * self.sys_params.pointer_size, + self.sys_params.types_cache.addr_ptr_type) + if not( + Utilities.is_valid_pointer( + self.superclassIsaPointer, + self.sys_params.pointer_size, + allow_tagged=0, + allow_NULL=1)): + logger >> "Marking as invalid - superclassIsa is invalid" + self.valid = 0 + return + + self.namePointer = Utilities.read_child_of( + self.valobj, + 2 * self.sys_params.pointer_size, + self.sys_params.types_cache.addr_ptr_type) + # if not(Utilities.is_valid_pointer(self.namePointer,self.sys_params.pointer_size,allow_tagged=0,allow_NULL=0)): + # self.valid = 0 + # return + + # in general, KVO is implemented by transparently subclassing + # however, there could be exceptions where a class does something else + # internally to implement the feature - this method will have no clue that a class + # has been KVO'ed unless the standard implementation technique is used + def is_kvo(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + if self.class_name().startswith("NSKVONotifying_"): + return 1 + return 0 + + # some CF classes have a valid ObjC isa in their CFRuntimeBase + # but instead of being class-specific this isa points to a match-'em-all class + # which is __NSCFType (the versions without __ also exists and we are matching to it + # just to be on the safe side) + def is_cftype(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + return self.class_name() == '__NSCFType' or self.class_name() == 'NSCFType' + + def get_superclass(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + parent_isa_pointer = self.valobj.CreateChildAtOffset( + "parent_isa", self.sys_params.pointer_size, self.sys_params.addr_ptr_type) + return Class_Data_V1(parent_isa_pointer, self.sys_params) + else: + return None + + def class_name(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + return self.name + else: + return None + + def is_valid(self): + return self.valid + + def __str__(self): + logger = lldb.formatters.Logger.Logger() + return 'isaPointer = ' + hex(self.isaPointer) + "\n" + \ + "superclassIsaPointer = " + hex(self.superclassIsaPointer) + "\n" + \ + "namePointer = " + hex(self.namePointer) + " --> " + self.name + \ + "instanceSize = " + hex(self.instanceSize()) + "\n" + + def is_tagged(self): + return 0 + + def instance_size(self, align=0): + logger = lldb.formatters.Logger.Logger() + if self.is_valid() == 0: + return None + if self.instanceSize is None: + self.instanceSize = Utilities.read_child_of( + self.valobj, + 5 * self.sys_params.pointer_size, + self.sys_params.types_cache.addr_ptr_type) + if align: + unalign = self.instance_size(0) + if self.sys_params.is_64_bit: + return ((unalign + 7) & ~7) % 0x100000000 + else: + return ((unalign + 3) & ~3) % 0x100000000 + else: + return self.instanceSize + +# these are the only tagged pointers values for current versions +# of OSX - they might change in future OS releases, and no-one is +# advised to rely on these values, or any of the bitmasking formulas +# in TaggedClass_Data. doing otherwise is at your own risk +TaggedClass_Values_Lion = {1: 'NSNumber', + 5: 'NSManagedObject', + 6: 'NSDate', + 7: 'NSDateTS'} +TaggedClass_Values_NMOS = {0: 'NSAtom', + 3: 'NSNumber', + 4: 'NSDateTS', + 5: 'NSManagedObject', + 6: 'NSDate'} + + +class TaggedClass_Data: + + def __init__(self, pointer, params): + logger = lldb.formatters.Logger.Logger() + global TaggedClass_Values_Lion, TaggedClass_Values_NMOS + self.valid = 1 + self.name = None + self.sys_params = params + self.valobj = pointer + self.val = (pointer & ~0x0000000000000000FF) >> 8 + self.class_bits = (pointer & 0xE) >> 1 + self.i_bits = (pointer & 0xF0) >> 4 + + if self.sys_params.is_lion: + if self.class_bits in TaggedClass_Values_Lion: + self.name = TaggedClass_Values_Lion[self.class_bits] + else: + logger >> "Marking as invalid - not a good tagged pointer for Lion" + self.valid = 0 + else: + if self.class_bits in TaggedClass_Values_NMOS: + self.name = TaggedClass_Values_NMOS[self.class_bits] + else: + logger >> "Marking as invalid - not a good tagged pointer for NMOS" + self.valid = 0 + + def is_valid(self): + return self.valid + + def class_name(self): + logger = lldb.formatters.Logger.Logger() + if self.is_valid(): + return self.name + else: + return 0 + + def value(self): + return self.val if self.is_valid() else None + + def info_bits(self): + return self.i_bits if self.is_valid() else None + + def is_kvo(self): + return 0 + + def is_cftype(self): + return 0 + + # we would need to go around looking for the superclass or ask the runtime + # for now, we seem not to require support for this operation so we will merrily + # pretend to be at a root point in the hierarchy + def get_superclass(self): + return None + + # anything that is handled here is tagged + def is_tagged(self): + return 1 + + # it seems reasonable to say that a tagged pointer is the size of a pointer + def instance_size(self, align=0): + logger = lldb.formatters.Logger.Logger() + if self.is_valid() == 0: + return None + return self.sys_params.pointer_size + + +class InvalidClass_Data: + + def __init__(self): + pass + + def is_valid(self): + return 0 + + +class Version: + + def __init__(self, major, minor, release, build_string): + self._major = major + self._minor = minor + self._release = release + self._build_string = build_string + + def get_major(self): + return self._major + + def get_minor(self): + return self._minor + + def get_release(self): + return self._release + + def get_build_string(self): + return self._build_string + + major = property(get_major, None) + minor = property(get_minor, None) + release = property(get_release, None) + build_string = property(get_build_string, None) + + def __lt__(self, other): + if (self.major < other.major): + return 1 + if (self.minor < other.minor): + return 1 + if (self.release < other.release): + return 1 + # build strings are not compared since they are heavily platform-dependent and might not always + # be available + return 0 + + def __eq__(self, other): + return (self.major == other.major) and \ + (self.minor == other.minor) and \ + (self.release == other.release) and \ + (self.build_string == other.build_string) + + # Python 2.6 doesn't have functools.total_ordering, so we have to implement + # other comparators + def __gt__(self, other): + return other < self + + def __le__(self, other): + return not other < self + + def __ge__(self, other): + return not self < other + + +runtime_version = lldb.formatters.cache.Cache() +os_version = lldb.formatters.cache.Cache() +types_caches = lldb.formatters.cache.Cache() +isa_caches = lldb.formatters.cache.Cache() + + +class SystemParameters: + + def __init__(self, valobj): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture(valobj) + self.adjust_for_process(valobj) + + def adjust_for_process(self, valobj): + logger = lldb.formatters.Logger.Logger() + global runtime_version + global os_version + global types_caches + global isa_caches + + process = valobj.GetTarget().GetProcess() + # using the unique ID for added guarantees (see svn revision 172628 for + # further details) + self.pid = process.GetUniqueID() + + if runtime_version.look_for_key(self.pid): + self.runtime_version = runtime_version.get_value(self.pid) + else: + self.runtime_version = ObjCRuntime.runtime_version(process) + runtime_version.add_item(self.pid, self.runtime_version) + + if os_version.look_for_key(self.pid): + self.is_lion = os_version.get_value(self.pid) + else: + self.is_lion = Utilities.check_is_osx_lion(valobj.GetTarget()) + os_version.add_item(self.pid, self.is_lion) + + if types_caches.look_for_key(self.pid): + self.types_cache = types_caches.get_value(self.pid) + else: + self.types_cache = lldb.formatters.attrib_fromdict.AttributesDictionary( + allow_reset=0) + self.types_cache.addr_type = valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedLong) + self.types_cache.addr_ptr_type = self.types_cache.addr_type.GetPointerType() + self.types_cache.uint32_t = valobj.GetType( + ).GetBasicType(lldb.eBasicTypeUnsignedInt) + types_caches.add_item(self.pid, self.types_cache) + + if isa_caches.look_for_key(self.pid): + self.isa_cache = isa_caches.get_value(self.pid) + else: + self.isa_cache = lldb.formatters.cache.Cache() + isa_caches.add_item(self.pid, self.isa_cache) + + def adjust_for_architecture(self, valobj): + process = valobj.GetTarget().GetProcess() + self.pointer_size = process.GetAddressByteSize() + self.is_64_bit = (self.pointer_size == 8) + self.endianness = process.GetByteOrder() + self.is_little = (self.endianness == lldb.eByteOrderLittle) + self.cfruntime_size = 16 if self.is_64_bit else 8 + + # a simple helper function that makes it more explicit that one is calculating + # an offset that is made up of X pointers and Y bytes of additional data + # taking into account pointer size - if you know there is going to be some padding + # you can pass that in and it will be taken into account (since padding may be different between + # 32 and 64 bit versions, you can pass padding value for both, the right + # one will be used) + def calculate_offset( + self, + num_pointers=0, + bytes_count=0, + padding32=0, + padding64=0): + value = bytes_count + num_pointers * self.pointer_size + return value + padding64 if self.is_64_bit else value + padding32 + + +class ObjCRuntime: + + # the ObjC runtime has no explicit "version" field that we can use + # instead, we discriminate v1 from v2 by looking for the presence + # of a well-known section only present in v1 + @staticmethod + def runtime_version(process): + logger = lldb.formatters.Logger.Logger() + if process.IsValid() == 0: + logger >> "No process - bailing out" + return None + target = process.GetTarget() + num_modules = target.GetNumModules() + module_objc = None + for idx in range(num_modules): + module = target.GetModuleAtIndex(idx) + if module.GetFileSpec().GetFilename() == 'libobjc.A.dylib': + module_objc = module + break + if module_objc is None or module_objc.IsValid() == 0: + logger >> "no libobjc - bailing out" + return None + num_sections = module.GetNumSections() + section_objc = None + for idx in range(num_sections): + section = module.GetSectionAtIndex(idx) + if section.GetName() == '__OBJC': + section_objc = section + break + if section_objc is not None and section_objc.IsValid(): + logger >> "found __OBJC: v1" + return 1 + logger >> "no __OBJC: v2" + return 2 + + @staticmethod + def runtime_from_isa(isa): + logger = lldb.formatters.Logger.Logger() + runtime = ObjCRuntime(isa) + runtime.isa = isa + return runtime + + def __init__(self, valobj): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.adjust_for_architecture() + self.sys_params = SystemParameters(self.valobj) + self.unsigned_value = self.valobj.GetValueAsUnsigned() + self.isa_value = None + + def adjust_for_architecture(self): + pass + +# an ObjC pointer can either be tagged or must be aligned + def is_tagged(self): + logger = lldb.formatters.Logger.Logger() + if self.valobj is None: + return 0 + return ( + Utilities.is_valid_pointer( + self.unsigned_value, + self.sys_params.pointer_size, + allow_tagged=1) and not( + Utilities.is_valid_pointer( + self.unsigned_value, + self.sys_params.pointer_size, + allow_tagged=0))) + + def is_valid(self): + logger = lldb.formatters.Logger.Logger() + if self.valobj is None: + return 0 + if self.valobj.IsInScope() == 0: + return 0 + return Utilities.is_valid_pointer( + self.unsigned_value, + self.sys_params.pointer_size, + allow_tagged=1) + + def is_nil(self): + return self.unsigned_value == 0 + + def read_isa(self): + logger = lldb.formatters.Logger.Logger() + if self.isa_value is not None: + logger >> "using cached isa" + return self.isa_value + self.isa_pointer = self.valobj.CreateChildAtOffset( + "cfisa", 0, self.sys_params.types_cache.addr_ptr_type) + if self.isa_pointer is None or self.isa_pointer.IsValid() == 0: + logger >> "invalid isa - bailing out" + return None + self.isa_value = self.isa_pointer.GetValueAsUnsigned(1) + if self.isa_value == 1: + logger >> "invalid isa value - bailing out" + return None + return Ellipsis + + def read_class_data(self): + logger = lldb.formatters.Logger.Logger() + global isa_cache + if self.is_tagged(): + # tagged pointers only exist in ObjC v2 + if self.sys_params.runtime_version == 2: + logger >> "on v2 and tagged - maybe" + # not every odd-valued pointer is actually tagged. most are just plain wrong + # we could try and predetect this before even creating a TaggedClass_Data object + # but unless performance requires it, this seems a cleaner way + # to tackle the task + tentative_tagged = TaggedClass_Data( + self.unsigned_value, self.sys_params) + if tentative_tagged.is_valid(): + logger >> "truly tagged" + return tentative_tagged + else: + logger >> "not tagged - error" + return InvalidClass_Data() + else: + logger >> "on v1 and tagged - error" + return InvalidClass_Data() + if self.is_valid() == 0 or self.read_isa() is None: + return InvalidClass_Data() + data = self.sys_params.isa_cache.get_value( + self.isa_value, default=None) + if data is not None: + return data + if self.sys_params.runtime_version == 2: + data = Class_Data_V2(self.isa_pointer, self.sys_params) + else: + data = Class_Data_V1(self.isa_pointer, self.sys_params) + if data is None: + return InvalidClass_Data() + if data.is_valid(): + self.sys_params.isa_cache.add_item( + self.isa_value, data, ok_to_replace=1) + return data + +# these classes below can be used by the data formatters to provide a +# consistent message that describes a given runtime-generated situation + + +class SpecialSituation_Description: + + def message(self): + return '' + + +class InvalidPointer_Description(SpecialSituation_Description): + + def __init__(self, nil): + self.is_nil = nil + + def message(self): + if self.is_nil: + return '@""' + else: + return '' + + +class InvalidISA_Description(SpecialSituation_Description): + + def __init__(self): + pass + + def message(self): + return '' + + +class ThisIsZombie_Description(SpecialSituation_Description): + + def message(self): + return '' diff --git a/examples/summaries/essentials b/examples/summaries/essentials new file mode 100644 index 000000000..85e87e234 --- /dev/null +++ b/examples/summaries/essentials @@ -0,0 +1,5 @@ +type summary add -s "${var._M_dataplus._M_p}" std::string std::basic_string "std::basic_string,std::allocator >" +type summary add -s "\"${var%@}\"" "NSString *" +type summary add -s "${svar%#} items" -e -x std::map< +type summary add -s "${svar%#} items" -e -x std::vector< +type summary add -s "${svar%#} items" -e -x std::list< diff --git a/examples/summaries/lldb b/examples/summaries/lldb new file mode 100644 index 000000000..b6b2bf3d4 --- /dev/null +++ b/examples/summaries/lldb @@ -0,0 +1,28 @@ +type summary add -w lldb lldb_private::Error -s "Type: ${var.m_type%E}, Code: ${var.m_code}, Message: ${var.m_string}" +type summary add -w lldb lldb_private::ConstString -s "${var.m_string}" +type summary add -w lldb lldb_private::Language -s "${var.m_language%E}" +type summary add -w lldb lldb_private::RegularExpression -s "${var.m_re}" +type summary add -w lldb lldb_private::UserID -s "UserID(${var.m_uid})" +type summary add -w lldb lldb_private::ValueObject -s "${var.m_name}" +type summary add -w lldb lldb_private::ValueObjectSP -s "${var.ptr_.m_name}" +type summary add -w lldb lldb_private::ValueObjectRegister -s "${var.m_reg_info.name}" +type summary add -w lldb lldb_private::ClangExpression -s "{${var.m_expr_text}}" +type summary add -w lldb lldb_private::CommandObject -s "Command name: ${var.m_cmd_name}" +type summary add -w lldb lldb_private::Variable -s "${var.m_type.m_name} ${var.m_name}" +type summary add -w lldb lldb_private::StopInfo -s "ID: ${var.m_stop_id}, ${var.m_description}" +type summary add -w lldb lldb_private::FileSpec -s "file: ${var.m_filename%S} dir: ${var.m_directory%S}" +type summary add -w -v lldb lldb::ConnectionStatus -s "[enum=${var%E} val=${var%i}]" +# Where '-v' tells type summary not to show the value itself, but just use the summary format. + +type summary add -w lldb "lldb_private::ThreadSafeValue" -s "${var.m_value}" +type summary add -w lldb lldb_private::CompileUnit -s "file: ${var.m_filename%S} dir: ${var.m_directory%S}" +type summary add -w lldb "lldb_private::Module" -s "${var.m_file%S}" +type summary add -w lldb "lldb_private::ModuleSpec" -s "${var.m_file%S}" +type summary add -w lldb "lldb_private::ModuleList" -s "${var.m_modules%S}" +type summary add -w lldb "lldb::ModuleSP" -s "${var._M_ptr%S}" +type summary add -w lldb "lldb_private::Process" -s "Public: ${var.m_public_state%S} Private: ${var.m_private_state%S}" +type summary add -w lldb "DynamicLoaderMacOSXDYLD::DYLDImageInfo" -s "${var.file_spec%S}" + +type format add -f x lldb::addr_t + +type category enable lldb diff --git a/examples/summaries/objc.py b/examples/summaries/objc.py new file mode 100644 index 000000000..486a9c821 --- /dev/null +++ b/examples/summaries/objc.py @@ -0,0 +1,19 @@ +# Summaries for common ObjC types that require Python scripting +# to be generated fit into this file + + +def BOOL_SummaryProvider(valobj, dict): + if not (valobj.IsValid()): + return "" + if valobj.GetValueAsUnsigned() == 0: + return "NO" + else: + return "YES" + + +def BOOLRef_SummaryProvider(valobj, dict): + return BOOL_SummaryProvider(valobj.GetChildAtIndex(0), dict) + + +def BOOLPtr_SummaryProvider(valobj, dict): + return BOOL_SummaryProvider(valobj.Dereference(), dict) diff --git a/examples/summaries/pysummary.py b/examples/summaries/pysummary.py new file mode 100644 index 000000000..22dffd6ca --- /dev/null +++ b/examples/summaries/pysummary.py @@ -0,0 +1,24 @@ +import lldb + + +def pyobj_summary(value, unused): + if value is None or value.IsValid() == False or value.GetValueAsUnsigned(0) == 0: + return "" + refcnt = value.GetChildMemberWithName("ob_refcnt") + expr = "(char*)PyString_AsString( (PyObject*)PyObject_Str( (PyObject*)0x%x) )" % ( + value.GetValueAsUnsigned(0)) + expr_summary = value.target.EvaluateExpression( + expr, lldb.SBExpressionOptions()).GetSummary() + refcnt_value = "rc = %d" % (refcnt.GetValueAsUnsigned(0)) + return "%s (%s)" % (expr_summary, refcnt_value) + + +def __lldb_init_module(debugger, unused): + debugger.HandleCommand( + "type summary add PyObject --python-function pysummary.pyobj_summary") + debugger.HandleCommand( + "type summary add lldb_private::PythonObject -s ${var.m_py_obj%S}") + debugger.HandleCommand( + "type summary add lldb_private::PythonDictionary -s ${var.m_py_obj%S}") + debugger.HandleCommand( + "type summary add lldb_private::PythonString -s ${var.m_py_obj%S}") diff --git a/examples/summaries/sp_cp.py b/examples/summaries/sp_cp.py new file mode 100644 index 000000000..e2ef18bfe --- /dev/null +++ b/examples/summaries/sp_cp.py @@ -0,0 +1,84 @@ +""" +Summary and synthetic providers for LLDB-specific shared pointers + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" + + +class SharedPtr_SyntheticChildrenProvider: + + def __init__(self, valobj, dict): + self.valobj = valobj + self.update() + + def update(self): + pass + + def num_children(self): + return 1 + + def get_child_index(self, name): + if name == "ptr": + return 0 + if name == "count": + return 1 + return None + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName('_M_ptr') + if index == 1: + return self.valobj.GetChildMemberWithName('_M_refcount').GetChildMemberWithName( + '_M_pi').GetChildMemberWithName('_M_use_count') + return None + + +def SharedPtr_SummaryProvider(valobj, dict): + return 'use = ' + \ + str(valobj.GetChildMemberWithName("count").GetValueAsUnsigned()) + + +class ValueObjectSP_SyntheticChildrenProvider: + + def __init__(self, valobj, dict): + self.valobj = valobj + self.update() + + def update(self): + pass + + def num_children(self): + return 1 + + def get_child_index(self, name): + if name == "ptr": + return 0 + if name == "count": + return 1 + return None + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName('ptr_') + if index == 1: + return self.valobj.GetChildMemberWithName( + 'cntrl_').GetChildMemberWithName('shared_owners_') + return None + + +def ValueObjectSP_SummaryProvider(valobj, dict): + return 'use = ' + \ + str(1 + valobj.GetChildMemberWithName("count").GetValueAsUnsigned()) + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + 'type summary add -x ".*ValueObjectSP" --expand -F sp_cp.ValueObjectSP_SummaryProvider') + debugger.HandleCommand( + 'type synthetic add -x ".*ValueObjectSP" -l sp_cp.ValueObjectSP_SyntheticChildrenProvider') + debugger.HandleCommand( + 'type summary add -x ".*SP" --expand -F sp_cp.SharedPtr_SummaryProvider') + debugger.HandleCommand( + 'type synthetic add -x ".*SP" -l sp_cp.SharedPtr_SyntheticChildrenProvider') diff --git a/examples/summaries/synth.py b/examples/summaries/synth.py new file mode 100644 index 000000000..23f02d9b5 --- /dev/null +++ b/examples/summaries/synth.py @@ -0,0 +1,66 @@ +import lldb + + +class PythonObjectSyntheticChildProvider(object): + + def __init__(self, value, internal_dict): + self.value = value + self.values = self.make_children() + self.built_values = {} + self.bo = self.value.target.byte_order + self.ps = self.value.target.addr_size + + def make_children(self): + pass + + def num_children(self): + return len(self.values) + + def get_child_index(self, name): + i = 0 + for N, value in self.values: + if N == name: + return i + i += 1 + return None + + def update(self): + pass + + def has_children(self): + return len(self.values) > 0 + + def gen_child(self, name, value): + data = None + type = None + if isinstance(value, int): + data = lldb.SBData.CreateDataFromUInt32Array( + self.bo, self.ps, [value]) + type = self.value.target.GetBasicType(lldb.eBasicTypeInt) + elif isinstance(value, long): + data = lldb.SBData.CreateDataFromUInt64Array( + self.bo, self.ps, [value]) + type = self.value.target.GetBasicType(lldb.eBasicTypeLong) + elif isinstance(value, float): + data = lldb.SBData.CreateDataFromDoubleArray( + self.bo, self.ps, [value]) + type = self.value.target.GetBasicType(lldb.eBasicTypeDouble) + elif isinstance(value, str): + data = lldb.SBData.CreateDataFromCString(self.bo, self.ps, value) + type = self.value.target.GetBasicType( + lldb.eBasicTypeChar).GetArrayType( + len(value)) + if (data is not None) and (type is not None): + return self.value.CreateValueFromData(name, data, type) + return None + + def get_child_at_index(self, index): + if index in self.built_values: + return self.built_values[index] + + bv = None + + name, value = self.values[index] + bv = self.gen_child(name, value) + self.built_values[index] = bv + return bv diff --git a/examples/summaries/unicode_strings.py b/examples/summaries/unicode_strings.py new file mode 100644 index 000000000..a9ba15a10 --- /dev/null +++ b/examples/summaries/unicode_strings.py @@ -0,0 +1,53 @@ +""" +Example data formatters for strings represented as (pointer,length) pairs +encoded in UTF8/16/32 for use with the LLDB debugger + +To use in your projects, tweak the children names as appropriate for your data structures +and use as summaries for your data types + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" + +import lldb + + +def utf8_summary(value, unused): + pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0) + length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0) + if pointer == 0: + return False + if length == 0: + return '""' + error = lldb.SBError() + string_data = value.process.ReadMemory(pointer, length, error) + return '"%s"' % (string_data) # utf8 is safe to emit as-is on OSX + + +def utf16_summary(value, unused): + pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0) + length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0) + # assume length is in bytes - if in UTF16 chars, just multiply by 2 + if pointer == 0: + return False + if length == 0: + return '""' + error = lldb.SBError() + string_data = value.process.ReadMemory(pointer, length, error) + # utf8 is safe to emit as-is on OSX + return '"%s"' % (string_data.decode('utf-16').encode('utf-8')) + + +def utf32_summary(value, unused): + pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0) + length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0) + # assume length is in bytes - if in UTF32 chars, just multiply by 4 + if pointer == 0: + return False + if length == 0: + return '""' + error = lldb.SBError() + string_data = value.process.ReadMemory(pointer, length, error) + # utf8 is safe to emit as-is on OSX + return '"%s"' % (string_data.decode('utf-32').encode('utf-8')) diff --git a/examples/synthetic/bitfield/example.py b/examples/synthetic/bitfield/example.py new file mode 100644 index 000000000..57bbf0f76 --- /dev/null +++ b/examples/synthetic/bitfield/example.py @@ -0,0 +1,123 @@ +# Synthetic children provider example for class MaskedData +# to use me: +# command script import ./example.py --allow-reload +# type synthetic add MaskedData --python-class +# example.MaskedData_SyntheticChildrenProvider + + +class MaskedData_SyntheticChildrenProvider: + + def __init__(self, valobj, dict): + # remember the SBValue since you will not have another chance to get it + # :-) + self.valobj = valobj + + def num_children(self): + # you could perform calculations involving the SBValue and/or its children to determine this value + # here, we have an hardcoded value - but since you have stored the SBValue you could use it to + # help figure out the correct thing to return here. if you return a number N, you should be prepared to + # answer questions about N children + return 4 + + def has_children(self): + # we simply say True here because we know we have 4 children + # in general, you want to make this calculation as simple as possible + # and return True if in doubt (you can always return num_children == 0 + # later) + return True + + def get_child_index(self, name): + # given a name, return its index + # you can return None if you don't know the answer for a given name + if name == "value": + return 0 + # here, we are using a reserved C++ keyword as a child name - we could not do that in the source code + # but we are free to use the names we like best in the synthetic children provider class + # we are also not respecting the order of declaration in the C++ class itself - as long as + # we are consistent, we can do that freely + if name == "operator": + return 1 + if name == "mask": + return 2 + # this member does not exist in the original class - we will compute its value and show it to the user + # when returning synthetic children, there is no need to only stick to + # what already exists in memory + if name == "apply()": + return 3 + return None # no clue, just say none + + def get_child_at_index(self, index): + # precautionary measures + if index < 0: + return None + if index > self.num_children(): + return None + if self.valobj.IsValid() == False: + return None + if index == 0: + return self.valobj.GetChildMemberWithName("value") + if index == 1: + # fetch the value of the operator + op_chosen = self.valobj.GetChildMemberWithName( + "oper").GetValueAsUnsigned() + # if it is a known value, return a descriptive string for it + # we are not doing this in the most efficient possible way, but the code is very readable + # and easy to maintain - if you change the values on the C++ side, + # the same changes must be made here + if op_chosen == 0: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"none"') + elif op_chosen == 1: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"AND"') + elif op_chosen == 2: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"OR"') + elif op_chosen == 3: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"XOR"') + elif op_chosen == 4: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"NAND"') + elif op_chosen == 5: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"NOR"') + else: + return self.valobj.CreateValueFromExpression( + "operator", '(const char*)"unknown"') # something else + if index == 2: + return self.valobj.GetChildMemberWithName("mask") + if index == 3: + # for this, we must fetch all the other elements + # in an efficient implementation, we would be caching this data for + # efficiency + value = self.valobj.GetChildMemberWithName( + "value").GetValueAsUnsigned() + operator = self.valobj.GetChildMemberWithName( + "oper").GetValueAsUnsigned() + mask = self.valobj.GetChildMemberWithName( + "mask").GetValueAsUnsigned() + # compute the masked value according to the operator + if operator == 1: + value = value & mask + elif operator == 2: + value = value | mask + elif operator == 3: + value = value ^ mask + elif operator == 4: + value = ~(value & mask) + elif operator == 5: + value = ~(value | mask) + else: + pass + value &= 0xFFFFFFFF # make sure Python does not extend our values to 64-bits + # return it - again, not the most efficient possible way. we should actually be pushing the computed value + # into an SBData, and using the SBData to create an SBValue - this + # has the advantage of readability + return self.valobj.CreateValueFromExpression( + "apply()", '(uint32_t)(' + str(value) + ')') + + def update(self): + # we do not do anything special in update - but this would be the right place to lookup + # the data we use in get_child_at_index and cache it + pass diff --git a/examples/synthetic/bitfield/program.cpp b/examples/synthetic/bitfield/program.cpp new file mode 100644 index 000000000..1db4aa4e7 --- /dev/null +++ b/examples/synthetic/bitfield/program.cpp @@ -0,0 +1,56 @@ +typedef unsigned int uint32_t; + +enum MaskingOperator { + eMaskingOperatorDefault = 0, + eMaskingOperatorAnd = 1, + eMaskingOperatorOr = 2, + eMaskingOperatorXor = 3, + eMaskingOperatorNand = 4, + eMaskingOperatorNor = 5 +}; + +class MaskedData { +private: + uint32_t value; + uint32_t mask; + MaskingOperator oper; + +public: + MaskedData(uint32_t V = 0, uint32_t M = 0, + MaskingOperator P = eMaskingOperatorDefault) + : value(V), mask(M), oper(P) {} + + uint32_t apply() { + switch (oper) { + case eMaskingOperatorAnd: + return value & mask; + case eMaskingOperatorOr: + return value | mask; + case eMaskingOperatorXor: + return value ^ mask; + case eMaskingOperatorNand: + return ~(value & mask); + case eMaskingOperatorNor: + return ~(value | mask); + case eMaskingOperatorDefault: // fall through + default: + return value; + } + } + + void setValue(uint32_t V) { value = V; } + + void setMask(uint32_t M) { mask = M; } + + void setOperator(MaskingOperator P) { oper = P; } +}; + +int main() { + MaskedData data_1(0xFF0F, 0xA01F, eMaskingOperatorAnd); + MaskedData data_2(data_1.apply(), 0x1AFC, eMaskingOperatorXor); + MaskedData data_3(data_2.apply(), 0xFFCF, eMaskingOperatorOr); + MaskedData data_4(data_3.apply(), 0xAABC, eMaskingOperatorAnd); + MaskedData data_5(data_4.apply(), 0xFFAC, eMaskingOperatorNor); + MaskedData data_6(data_5.apply(), 0x0000BEEF, eMaskingOperatorAnd); + return data_6.apply(); // <-- what comes out of here? +} \ No newline at end of file diff --git a/examples/synthetic/gnu_libstdcpp.py b/examples/synthetic/gnu_libstdcpp.py new file mode 100644 index 000000000..becf168f4 --- /dev/null +++ b/examples/synthetic/gnu_libstdcpp.py @@ -0,0 +1,480 @@ +import re +import lldb.formatters.Logger + +# C++ STL formatters for LLDB +# These formatters are based upon the version of the GNU libstdc++ +# as it ships with Mac OS X 10.6.8 thru 10.8.0 +# You are encouraged to look at the STL implementation for your platform +# before relying on these formatters to do the right thing for your setup + + +class StdListSynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.count = None + logger >> "Providing synthetic children for a list named " + \ + str(valobj.GetName()) + + def next_node(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetChildMemberWithName('_M_next') + + def is_valid(self, node): + logger = lldb.formatters.Logger.Logger() + valid = self.value(self.next_node(node)) != self.node_address + if valid: + logger >> "%s is valid" % str(self.valobj.GetName()) + else: + logger >> "synthetic value is not valid" + return valid + + def value(self, node): + logger = lldb.formatters.Logger.Logger() + value = node.GetValueAsUnsigned() + logger >> "synthetic value for {}: {}".format( + str(self.valobj.GetName()), value) + return value + + # Floyd's cycle-finding algorithm + # try to detect if this list has a loop + def has_loop(self): + global _list_uses_loop_detector + logger = lldb.formatters.Logger.Logger() + if not _list_uses_loop_detector: + logger >> "Asked not to use loop detection" + return False + slow = self.next + fast1 = self.next + fast2 = self.next + while self.is_valid(slow): + slow_value = self.value(slow) + fast1 = self.next_node(fast2) + fast2 = self.next_node(fast1) + if self.value(fast1) == slow_value or self.value( + fast2) == slow_value: + return True + slow = self.next_node(slow) + return False + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + if self.count is None: + # libstdc++ 6.0.21 added dedicated count field. + count_child = self.node.GetChildMemberWithName('_M_data') + if count_child and count_child.IsValid(): + self.count = count_child.GetValueAsUnsigned(0) + if self.count is None: + self.count = self.num_children_impl() + return self.count + + def num_children_impl(self): + logger = lldb.formatters.Logger.Logger() + try: + next_val = self.next.GetValueAsUnsigned(0) + prev_val = self.prev.GetValueAsUnsigned(0) + # After a std::list has been initialized, both next and prev will + # be non-NULL + if next_val == 0 or prev_val == 0: + return 0 + if next_val == self.node_address: + return 0 + if next_val == prev_val: + return 1 + if self.has_loop(): + return 0 + size = 2 + current = self.next + while current.GetChildMemberWithName( + '_M_next').GetValueAsUnsigned(0) != self.node_address: + size = size + 1 + current = current.GetChildMemberWithName('_M_next') + return (size - 1) + except: + return 0 + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Fetching child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None + try: + offset = index + current = self.next + while offset > 0: + current = current.GetChildMemberWithName('_M_next') + offset = offset - 1 + return current.CreateChildAtOffset( + '[' + str(index) + ']', + 2 * current.GetType().GetByteSize(), + self.data_type) + except: + return None + + def extract_type(self): + logger = lldb.formatters.Logger.Logger() + list_type = self.valobj.GetType().GetUnqualifiedType() + if list_type.IsReferenceType(): + list_type = list_type.GetDereferencedType() + if list_type.GetNumberOfTemplateArguments() > 0: + data_type = list_type.GetTemplateArgumentType(0) + else: + data_type = None + return data_type + + def update(self): + logger = lldb.formatters.Logger.Logger() + # preemptively setting this to None - we might end up changing our mind + # later + self.count = None + try: + impl = self.valobj.GetChildMemberWithName('_M_impl') + self.node = impl.GetChildMemberWithName('_M_node') + self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) + self.next = self.node.GetChildMemberWithName('_M_next') + self.prev = self.node.GetChildMemberWithName('_M_prev') + self.data_type = self.extract_type() + self.data_size = self.data_type.GetByteSize() + except: + pass + + def has_children(self): + return True + + +class StdVectorSynthProvider: + + class StdVectorImplementation(object): + + def __init__(self, valobj): + self.valobj = valobj + self.count = None + + def num_children(self): + if self.count is None: + self.count = self.num_children_impl() + return self.count + + def num_children_impl(self): + try: + start_val = self.start.GetValueAsUnsigned(0) + finish_val = self.finish.GetValueAsUnsigned(0) + end_val = self.end.GetValueAsUnsigned(0) + # Before a vector has been constructed, it will contain bad values + # so we really need to be careful about the length we return since + # uninitialized data can cause us to return a huge number. We need + # to also check for any of the start, finish or end of storage values + # being zero (NULL). If any are, then this vector has not been + # initialized yet and we should return zero + + # Make sure nothing is NULL + if start_val == 0 or finish_val == 0 or end_val == 0: + return 0 + # Make sure start is less than finish + if start_val >= finish_val: + return 0 + # Make sure finish is less than or equal to end of storage + if finish_val > end_val: + return 0 + + # if we have a struct (or other data type that the compiler pads to native word size) + # this check might fail, unless the sizeof() we get is itself incremented to take the + # padding bytes into account - on current clang it looks like + # this is the case + num_children = (finish_val - start_val) + if (num_children % self.data_size) != 0: + return 0 + else: + num_children = num_children / self.data_size + return num_children + except: + return 0 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Retrieving child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None + try: + offset = index * self.data_size + return self.start.CreateChildAtOffset( + '[' + str(index) + ']', offset, self.data_type) + except: + return None + + def update(self): + # preemptively setting this to None - we might end up changing our + # mind later + self.count = None + try: + impl = self.valobj.GetChildMemberWithName('_M_impl') + self.start = impl.GetChildMemberWithName('_M_start') + self.finish = impl.GetChildMemberWithName('_M_finish') + self.end = impl.GetChildMemberWithName('_M_end_of_storage') + self.data_type = self.start.GetType().GetPointeeType() + self.data_size = self.data_type.GetByteSize() + # if any of these objects is invalid, it means there is no + # point in trying to fetch anything + if self.start.IsValid() and self.finish.IsValid( + ) and self.end.IsValid() and self.data_type.IsValid(): + self.count = None + else: + self.count = 0 + except: + pass + return True + + class StdVBoolImplementation(object): + + def __init__(self, valobj, bool_type): + self.valobj = valobj + self.bool_type = bool_type + self.valid = False + + def num_children(self): + if self.valid: + start = self.start_p.GetValueAsUnsigned(0) + finish = self.finish_p.GetValueAsUnsigned(0) + offset = self.offset.GetValueAsUnsigned(0) + if finish >= start: + return (finish - start) * 8 + offset + return 0 + + def get_child_at_index(self, index): + if index >= self.num_children(): + return None + element_type = self.start_p.GetType().GetPointeeType() + element_bits = 8 * element_type.GetByteSize() + element_offset = (index / element_bits) * \ + element_type.GetByteSize() + bit_offset = index % element_bits + element = self.start_p.CreateChildAtOffset( + '[' + str(index) + ']', element_offset, element_type) + bit = element.GetValueAsUnsigned(0) & (1 << bit_offset) + if bit != 0: + value_expr = "(bool)true" + else: + value_expr = "(bool)false" + return self.valobj.CreateValueFromExpression( + "[%d]" % index, value_expr) + + def update(self): + try: + m_impl = self.valobj.GetChildMemberWithName('_M_impl') + self.m_start = m_impl.GetChildMemberWithName('_M_start') + self.m_finish = m_impl.GetChildMemberWithName('_M_finish') + self.start_p = self.m_start.GetChildMemberWithName('_M_p') + self.finish_p = self.m_finish.GetChildMemberWithName('_M_p') + self.offset = self.m_finish.GetChildMemberWithName('_M_offset') + self.valid = True + except: + self.valid = False + return True + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + first_template_arg_type = valobj.GetType().GetTemplateArgumentType(0) + if str(first_template_arg_type.GetName()) == "bool": + self.impl = self.StdVBoolImplementation( + valobj, first_template_arg_type) + else: + self.impl = self.StdVectorImplementation(valobj) + logger >> "Providing synthetic children for a vector named " + \ + str(valobj.GetName()) + + def num_children(self): + return self.impl.num_children() + + def get_child_index(self, name): + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + return self.impl.get_child_at_index(index) + + def update(self): + return self.impl.update() + + def has_children(self): + return True + + +class StdMapSynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.count = None + logger >> "Providing synthetic children for a map named " + \ + str(valobj.GetName()) + + # we need this function as a temporary workaround for rdar://problem/10801549 + # which prevents us from extracting the std::pair SBType out of the template + # arguments for _Rep_Type _M_t in the map itself - because we have to make up the + # typename and then find it, we may hit the situation were std::string has multiple + # names but only one is actually referenced in the debug information. hence, we need + # to replace the longer versions of std::string with the shorter one in order to be able + # to find the type name + def fixup_class_name(self, class_name): + logger = lldb.formatters.Logger.Logger() + if class_name == 'std::basic_string, std::allocator >': + return 'std::basic_string', True + if class_name == 'basic_string, std::allocator >': + return 'std::basic_string', True + if class_name == 'std::basic_string, std::allocator >': + return 'std::basic_string', True + if class_name == 'basic_string, std::allocator >': + return 'std::basic_string', True + return class_name, False + + def update(self): + logger = lldb.formatters.Logger.Logger() + # preemptively setting this to None - we might end up changing our mind + # later + self.count = None + try: + # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree + # if this gets set to True, then we will merrily return None for + # any child from that moment on + self.garbage = False + self.Mt = self.valobj.GetChildMemberWithName('_M_t') + self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl') + self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header') + + map_type = self.valobj.GetType() + if map_type.IsReferenceType(): + logger >> "Dereferencing type" + map_type = map_type.GetDereferencedType() + + # Get the type of std::pair. It is the first template + # argument type of the 4th template argument to std::map. + allocator_type = map_type.GetTemplateArgumentType(3) + self.data_type = allocator_type.GetTemplateArgumentType(0) + if not self.data_type: + # GCC does not emit DW_TAG_template_type_parameter for + # std::allocator<...>. For such a case, get the type of + # std::pair from a member of std::map. + rep_type = self.valobj.GetChildMemberWithName('_M_t').GetType() + self.data_type = rep_type.GetTypedefedType().GetTemplateArgumentType(1) + + # from libstdc++ implementation of _M_root for rbtree + self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent') + self.data_size = self.data_type.GetByteSize() + self.skip_size = self.Mheader.GetType().GetByteSize() + except: + pass + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + if self.count is None: + self.count = self.num_children_impl() + return self.count + + def num_children_impl(self): + logger = lldb.formatters.Logger.Logger() + try: + root_ptr_val = self.node_ptr_value(self.Mroot) + if root_ptr_val == 0: + return 0 + count = self.Mimpl.GetChildMemberWithName( + '_M_node_count').GetValueAsUnsigned(0) + logger >> "I have " + str(count) + " children available" + return count + except: + return 0 + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Being asked to fetch child[" + str(index) + "]" + if index < 0: + return None + if index >= self.num_children(): + return None + if self.garbage: + logger >> "Returning None since we are a garbage tree" + return None + try: + offset = index + current = self.left(self.Mheader) + while offset > 0: + current = self.increment_node(current) + offset = offset - 1 + # skip all the base stuff and get at the data + return current.CreateChildAtOffset( + '[' + str(index) + ']', self.skip_size, self.data_type) + except: + return None + + # utility functions + def node_ptr_value(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetValueAsUnsigned(0) + + def right(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetChildMemberWithName("_M_right") + + def left(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetChildMemberWithName("_M_left") + + def parent(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetChildMemberWithName("_M_parent") + + # from libstdc++ implementation of iterator for rbtree + def increment_node(self, node): + logger = lldb.formatters.Logger.Logger() + max_steps = self.num_children() + if self.node_ptr_value(self.right(node)) != 0: + x = self.right(node) + max_steps -= 1 + while self.node_ptr_value(self.left(x)) != 0: + x = self.left(x) + max_steps -= 1 + logger >> str(max_steps) + " more to go before giving up" + if max_steps <= 0: + self.garbage = True + return None + return x + else: + x = node + y = self.parent(x) + max_steps -= 1 + while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))): + x = y + y = self.parent(y) + max_steps -= 1 + logger >> str(max_steps) + " more to go before giving up" + if max_steps <= 0: + self.garbage = True + return None + if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y): + x = y + return x + + def has_children(self): + return True + +_list_uses_loop_detector = True diff --git a/examples/synthetic/libcxx.py b/examples/synthetic/libcxx.py new file mode 100644 index 000000000..e6f8223e2 --- /dev/null +++ b/examples/synthetic/libcxx.py @@ -0,0 +1,869 @@ +import lldb +import lldb.formatters.Logger + +# libcxx STL formatters for LLDB +# These formatters are based upon the implementation of libc++ that +# ships with current releases of OS X - They will not work for other implementations +# of the standard C++ library - and they are bound to use the +# libc++-specific namespace + +# the std::string summary is just an example for your convenience +# the actual summary that LLDB uses is C++ code inside the debugger's own core + +# this could probably be made more efficient but since it only reads a handful of bytes at a time +# we probably don't need to worry too much about this for the time being + + +def make_string(F, L): + strval = '' + G = F.GetData().uint8 + for X in range(L): + V = G[X] + if V == 0: + break + strval = strval + chr(V % 256) + return '"' + strval + '"' + +# if we ever care about big-endian, these two functions might need to change + + +def is_short_string(value): + return True if (value & 1) == 0 else False + + +def extract_short_size(value): + return ((value >> 1) % 256) + +# some of the members of libc++ std::string are anonymous or have internal names that convey +# no external significance - we access them by index since this saves a name lookup that would add +# no information for readers of the code, but when possible try to use +# meaningful variable names + + +def stdstring_SummaryProvider(valobj, dict): + logger = lldb.formatters.Logger.Logger() + r = valobj.GetChildAtIndex(0) + B = r.GetChildAtIndex(0) + first = B.GetChildAtIndex(0) + D = first.GetChildAtIndex(0) + l = D.GetChildAtIndex(0) + s = D.GetChildAtIndex(1) + D20 = s.GetChildAtIndex(0) + size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0) + if is_short_string(size_mode): + size = extract_short_size(size_mode) + return make_string(s.GetChildAtIndex(1), size) + else: + data_ptr = l.GetChildAtIndex(2) + size_vo = l.GetChildAtIndex(1) + # the NULL terminator must be accounted for + size = size_vo.GetValueAsUnsigned(0) + 1 + if size <= 1 or size is None: # should never be the case + return '""' + try: + data = data_ptr.GetPointeeData(0, size) + except: + return '""' + error = lldb.SBError() + strval = data.GetString(error, 0) + if error.Fail(): + return '' + else: + return '"' + strval + '"' + + +class stdvector_SynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + try: + start_val = self.start.GetValueAsUnsigned(0) + finish_val = self.finish.GetValueAsUnsigned(0) + # Before a vector has been constructed, it will contain bad values + # so we really need to be careful about the length we return since + # uninitialized data can cause us to return a huge number. We need + # to also check for any of the start, finish or end of storage values + # being zero (NULL). If any are, then this vector has not been + # initialized yet and we should return zero + + # Make sure nothing is NULL + if start_val == 0 or finish_val == 0: + return 0 + # Make sure start is less than finish + if start_val >= finish_val: + return 0 + + num_children = (finish_val - start_val) + if (num_children % self.data_size) != 0: + return 0 + else: + num_children = num_children / self.data_size + return num_children + except: + return 0 + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Retrieving child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None + try: + offset = index * self.data_size + return self.start.CreateChildAtOffset( + '[' + str(index) + ']', offset, self.data_type) + except: + return None + + def update(self): + logger = lldb.formatters.Logger.Logger() + try: + self.start = self.valobj.GetChildMemberWithName('__begin_') + self.finish = self.valobj.GetChildMemberWithName('__end_') + # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector + # if this ends up not being correct, we can use the APIs to get at + # template arguments + data_type_finder = self.valobj.GetChildMemberWithName( + '__end_cap_').GetChildMemberWithName('__first_') + self.data_type = data_type_finder.GetType().GetPointeeType() + self.data_size = self.data_type.GetByteSize() + except: + pass + + def has_children(self): + return True + +# Just an example: the actual summary is produced by a summary string: +# size=${svar%#} + + +def stdvector_SummaryProvider(valobj, dict): + prov = stdvector_SynthProvider(valobj, None) + return 'size=' + str(prov.num_children()) + + +class stdlist_entry: + + def __init__(self, entry): + logger = lldb.formatters.Logger.Logger() + self.entry = entry + + def _next_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdlist_entry(self.entry.GetChildMemberWithName('__next_')) + + def _prev_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdlist_entry(self.entry.GetChildMemberWithName('__prev_')) + + def _value_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.entry.GetValueAsUnsigned(0) + + def _isnull_impl(self): + logger = lldb.formatters.Logger.Logger() + return self._value_impl() == 0 + + def _sbvalue_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.entry + + next = property(_next_impl, None) + value = property(_value_impl, None) + is_null = property(_isnull_impl, None) + sbvalue = property(_sbvalue_impl, None) + + +class stdlist_iterator: + + def increment_node(self, node): + logger = lldb.formatters.Logger.Logger() + if node.is_null: + return None + return node.next + + def __init__(self, node): + logger = lldb.formatters.Logger.Logger() + # we convert the SBValue to an internal node object on entry + self.node = stdlist_entry(node) + + def value(self): + logger = lldb.formatters.Logger.Logger() + return self.node.sbvalue # and return the SBValue back on exit + + def next(self): + logger = lldb.formatters.Logger.Logger() + node = self.increment_node(self.node) + if node is not None and node.sbvalue.IsValid() and not(node.is_null): + self.node = node + return self.value() + else: + return None + + def advance(self, N): + logger = lldb.formatters.Logger.Logger() + if N < 0: + return None + if N == 0: + return self.value() + if N == 1: + return self.next() + while N > 0: + self.next() + N = N - 1 + return self.value() + + +class stdlist_SynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.count = None + + def next_node(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetChildMemberWithName('__next_') + + def value(self, node): + logger = lldb.formatters.Logger.Logger() + return node.GetValueAsUnsigned() + + # Floyd's cycle-finding algorithm + # try to detect if this list has a loop + def has_loop(self): + global _list_uses_loop_detector + logger = lldb.formatters.Logger.Logger() + if not _list_uses_loop_detector: + logger >> "Asked not to use loop detection" + return False + slow = stdlist_entry(self.head) + fast1 = stdlist_entry(self.head) + fast2 = stdlist_entry(self.head) + while slow.next.value != self.node_address: + slow_value = slow.value + fast1 = fast2.next + fast2 = fast1.next + if fast1.value == slow_value or fast2.value == slow_value: + return True + slow = slow.next + return False + + def num_children(self): + global _list_capping_size + logger = lldb.formatters.Logger.Logger() + if self.count is None: + self.count = self.num_children_impl() + if self.count > _list_capping_size: + self.count = _list_capping_size + return self.count + + def num_children_impl(self): + global _list_capping_size + logger = lldb.formatters.Logger.Logger() + try: + next_val = self.head.GetValueAsUnsigned(0) + prev_val = self.tail.GetValueAsUnsigned(0) + # After a std::list has been initialized, both next and prev will + # be non-NULL + if next_val == 0 or prev_val == 0: + return 0 + if next_val == self.node_address: + return 0 + if next_val == prev_val: + return 1 + if self.has_loop(): + return 0 + size = 2 + current = stdlist_entry(self.head) + while current.next.value != self.node_address: + size = size + 1 + current = current.next + if size > _list_capping_size: + return _list_capping_size + return (size - 1) + except: + return 0 + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Fetching child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None + try: + current = stdlist_iterator(self.head) + current = current.advance(index) + # we do not return __value_ because then all our children would be named __value_ + # we need to make a copy of __value__ with the right name - + # unfortunate + obj = current.GetChildMemberWithName('__value_') + obj_data = obj.GetData() + return self.valobj.CreateValueFromData( + '[' + str(index) + ']', obj_data, self.data_type) + except: + return None + + def extract_type(self): + logger = lldb.formatters.Logger.Logger() + list_type = self.valobj.GetType().GetUnqualifiedType() + if list_type.IsReferenceType(): + list_type = list_type.GetDereferencedType() + if list_type.GetNumberOfTemplateArguments() > 0: + data_type = list_type.GetTemplateArgumentType(0) + else: + data_type = None + return data_type + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.count = None + try: + impl = self.valobj.GetChildMemberWithName('__end_') + self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) + self.head = impl.GetChildMemberWithName('__next_') + self.tail = impl.GetChildMemberWithName('__prev_') + self.data_type = self.extract_type() + self.data_size = self.data_type.GetByteSize() + except: + pass + + def has_children(self): + return True + + +# Just an example: the actual summary is produced by a summary string: +# size=${svar%#} +def stdlist_SummaryProvider(valobj, dict): + prov = stdlist_SynthProvider(valobj, None) + return 'size=' + str(prov.num_children()) + +# a tree node - this class makes the syntax in the actual iterator nicer +# to read and maintain + + +class stdmap_iterator_node: + + def _left_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdmap_iterator_node( + self.node.GetChildMemberWithName("__left_")) + + def _right_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdmap_iterator_node( + self.node.GetChildMemberWithName("__right_")) + + def _parent_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdmap_iterator_node( + self.node.GetChildMemberWithName("__parent_")) + + def _value_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.node.GetValueAsUnsigned(0) + + def _sbvalue_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.node + + def _null_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.value == 0 + + def __init__(self, node): + logger = lldb.formatters.Logger.Logger() + self.node = node + + left = property(_left_impl, None) + right = property(_right_impl, None) + parent = property(_parent_impl, None) + value = property(_value_impl, None) + is_null = property(_null_impl, None) + sbvalue = property(_sbvalue_impl, None) + +# a Python implementation of the tree iterator used by libc++ + + +class stdmap_iterator: + + def tree_min(self, x): + logger = lldb.formatters.Logger.Logger() + steps = 0 + if x.is_null: + return None + while (not x.left.is_null): + x = x.left + steps += 1 + if steps > self.max_count: + logger >> "Returning None - we overflowed" + return None + return x + + def tree_max(self, x): + logger = lldb.formatters.Logger.Logger() + if x.is_null: + return None + while (not x.right.is_null): + x = x.right + return x + + def tree_is_left_child(self, x): + logger = lldb.formatters.Logger.Logger() + if x.is_null: + return None + return True if x.value == x.parent.left.value else False + + def increment_node(self, node): + logger = lldb.formatters.Logger.Logger() + if node.is_null: + return None + if not node.right.is_null: + return self.tree_min(node.right) + steps = 0 + while (not self.tree_is_left_child(node)): + steps += 1 + if steps > self.max_count: + logger >> "Returning None - we overflowed" + return None + node = node.parent + return node.parent + + def __init__(self, node, max_count=0): + logger = lldb.formatters.Logger.Logger() + # we convert the SBValue to an internal node object on entry + self.node = stdmap_iterator_node(node) + self.max_count = max_count + + def value(self): + logger = lldb.formatters.Logger.Logger() + return self.node.sbvalue # and return the SBValue back on exit + + def next(self): + logger = lldb.formatters.Logger.Logger() + node = self.increment_node(self.node) + if node is not None and node.sbvalue.IsValid() and not(node.is_null): + self.node = node + return self.value() + else: + return None + + def advance(self, N): + logger = lldb.formatters.Logger.Logger() + if N < 0: + return None + if N == 0: + return self.value() + if N == 1: + return self.next() + while N > 0: + if self.next() is None: + return None + N = N - 1 + return self.value() + + +class stdmap_SynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() + self.count = None + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.count = None + try: + # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree + # if this gets set to True, then we will merrily return None for + # any child from that moment on + self.garbage = False + self.tree = self.valobj.GetChildMemberWithName('__tree_') + self.root_node = self.tree.GetChildMemberWithName('__begin_node_') + # this data is either lazily-calculated, or cannot be inferred at this moment + # we still need to mark it as None, meaning "please set me ASAP" + self.data_type = None + self.data_size = None + self.skip_size = None + except: + pass + + def num_children(self): + global _map_capping_size + logger = lldb.formatters.Logger.Logger() + if self.count is None: + self.count = self.num_children_impl() + if self.count > _map_capping_size: + self.count = _map_capping_size + return self.count + + def num_children_impl(self): + logger = lldb.formatters.Logger.Logger() + try: + return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName( + '__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned() + except: + return 0 + + def has_children(self): + return True + + def get_data_type(self): + logger = lldb.formatters.Logger.Logger() + if self.data_type is None or self.data_size is None: + if self.num_children() == 0: + return False + deref = self.root_node.Dereference() + if not(deref.IsValid()): + return False + value = deref.GetChildMemberWithName('__value_') + if not(value.IsValid()): + return False + self.data_type = value.GetType() + self.data_size = self.data_type.GetByteSize() + self.skip_size = None + return True + else: + return True + + def get_value_offset(self, node): + logger = lldb.formatters.Logger.Logger() + if self.skip_size is None: + node_type = node.GetType() + fields_count = node_type.GetNumberOfFields() + for i in range(fields_count): + field = node_type.GetFieldAtIndex(i) + if field.GetName() == '__value_': + self.skip_size = field.GetOffsetInBytes() + break + return (self.skip_size is not None) + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Retrieving child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None + if self.garbage: + logger >> "Returning None since this tree is garbage" + return None + try: + iterator = stdmap_iterator( + self.root_node, max_count=self.num_children()) + # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type + # out of which we can grab the information we need - every other node has a less informative + # type which omits all value information and only contains housekeeping information for the RB tree + # hence, we need to know if we are at a node != 0, so that we can + # still get at the data + need_to_skip = (index > 0) + current = iterator.advance(index) + if current is None: + logger >> "Tree is garbage - returning None" + self.garbage = True + return None + if self.get_data_type(): + if not(need_to_skip): + current = current.Dereference() + obj = current.GetChildMemberWithName('__value_') + obj_data = obj.GetData() + # make sure we have a valid offset for the next items + self.get_value_offset(current) + # we do not return __value_ because then we would end up with a child named + # __value_ instead of [0] + return self.valobj.CreateValueFromData( + '[' + str(index) + ']', obj_data, self.data_type) + else: + # FIXME we need to have accessed item 0 before accessing + # any other item! + if self.skip_size is None: + logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry" + if self.get_child_at_index(0): + return self.get_child_at_index(index) + else: + logger >> "item == 0 could not be found. sorry, nothing can be done here." + return None + return current.CreateChildAtOffset( + '[' + str(index) + ']', self.skip_size, self.data_type) + else: + logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)" + return None + except Exception as err: + logger >> "Hit an exception: " + str(err) + return None + +# Just an example: the actual summary is produced by a summary string: +# size=${svar%#} + + +def stdmap_SummaryProvider(valobj, dict): + prov = stdmap_SynthProvider(valobj, None) + return 'size=' + str(prov.num_children()) + + +class stddeque_SynthProvider: + + def __init__(self, valobj, d): + logger = lldb.formatters.Logger.Logger() + logger.write("init") + self.valobj = valobj + self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() + self.count = None + try: + self.find_block_size() + except: + self.block_size = -1 + self.element_size = -1 + logger.write( + "block_size=%d, element_size=%d" % + (self.block_size, self.element_size)) + + def find_block_size(self): + # in order to use the deque we must have the block size, or else + # it's impossible to know what memory addresses are valid + self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + self.element_size = self.element_type.GetByteSize() + # The code says this, but there must be a better way: + # template + # class __deque_base { + # static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16; + # } + if self.element_size < 256: + self.block_size = 4096 / self.element_size + else: + self.block_size = 16 + + def num_children(self): + global _deque_capping_size + logger = lldb.formatters.Logger.Logger() + if self.count is None: + return 0 + return min(self.count, _deque_capping_size) + + def has_children(self): + return True + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger.write("Fetching child " + str(index)) + if index < 0 or self.count is None: + return None + if index >= self.num_children(): + return None + try: + i, j = divmod(self.start + index, self.block_size) + return self.first.CreateValueFromExpression( + '[' + str(index) + ']', '*(*(%s + %d) + %d)' % + (self.first.get_expr_path(), i, j)) + except: + return None + + def update(self): + logger = lldb.formatters.Logger.Logger() + try: + # A deque is effectively a two-dim array, with fixed width. + # 'map' contains pointers to the rows of this array. The + # full memory area allocated by the deque is delimited + # by 'first' and 'end_cap'. However, only a subset of this + # memory contains valid data since a deque may have some slack + # at the front and back in order to have O(1) insertion at + # both ends. The rows in active use are delimited by + # 'begin' and 'end'. + # + # To find the elements that are actually constructed, the 'start' + # variable tells which element in this NxM array is the 0th + # one, and the 'size' element gives the number of elements + # in the deque. + count = self.valobj.GetChildMemberWithName( + '__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + # give up now if we cant access memory reliably + if self.block_size < 0: + logger.write("block_size < 0") + return + map_ = self.valobj.GetChildMemberWithName('__map_') + start = self.valobj.GetChildMemberWithName( + '__start_').GetValueAsUnsigned(0) + first = map_.GetChildMemberWithName('__first_') + map_first = first.GetValueAsUnsigned(0) + map_begin = map_.GetChildMemberWithName( + '__begin_').GetValueAsUnsigned(0) + map_end = map_.GetChildMemberWithName( + '__end_').GetValueAsUnsigned(0) + map_endcap = map_.GetChildMemberWithName( + '__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + # check consistency + if not map_first <= map_begin <= map_end <= map_endcap: + logger.write("map pointers are not monotonic") + return + total_rows, junk = divmod( + map_endcap - map_first, self.pointer_size) + if junk: + logger.write("endcap-first doesnt align correctly") + return + active_rows, junk = divmod(map_end - map_begin, self.pointer_size) + if junk: + logger.write("end-begin doesnt align correctly") + return + start_row, junk = divmod(map_begin - map_first, self.pointer_size) + if junk: + logger.write("begin-first doesnt align correctly") + return + if not start_row * \ + self.block_size <= start < (start_row + 1) * self.block_size: + logger.write("0th element must be in the 'begin' row") + return + end_row = start_row + active_rows + if not count: + if active_rows: + logger.write("empty deque but begin!=end") + return + elif not (end_row - 1) * self.block_size <= start + count < end_row * self.block_size: + logger.write("nth element must be before the 'end' row") + return + logger.write( + "update success: count=%r, start=%r, first=%r" % + (count, start, first)) + # if consistent, save all we really need: + self.count = count + self.start = start + self.first = first + except: + self.count = None + self.start = None + self.map_first = None + self.map_begin = None + + +class stdsharedptr_SynthProvider: + + def __init__(self, valobj, d): + logger = lldb.formatters.Logger.Logger() + logger.write("init") + self.valobj = valobj + #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType() + self.ptr = None + self.cntrl = None + process = valobj.GetProcess() + self.endianness = process.GetByteOrder() + self.pointer_size = process.GetAddressByteSize() + self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) + + def num_children(self): + return 1 + + def has_children(self): + return True + + def get_child_index(self, name): + if name == "__ptr_": + return 0 + if name == "count": + return 1 + if name == "weak_count": + return 2 + return -1 + + def get_child_at_index(self, index): + if index == 0: + return self.ptr + if index == 1: + if self.cntrl is None: + count = 0 + else: + count = 1 + \ + self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned() + return self.valobj.CreateValueFromData( + "count", lldb.SBData.CreateDataFromUInt64Array( + self.endianness, self.pointer_size, [count]), self.count_type) + if index == 2: + if self.cntrl is None: + count = 0 + else: + count = 1 + \ + self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned() + return self.valobj.CreateValueFromData( + "weak_count", lldb.SBData.CreateDataFromUInt64Array( + self.endianness, self.pointer_size, [count]), self.count_type) + return None + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.ptr = self.valobj.GetChildMemberWithName( + '__ptr_') # .Cast(self.element_ptr_type) + cntrl = self.valobj.GetChildMemberWithName('__cntrl_') + if cntrl.GetValueAsUnsigned(0): + self.cntrl = cntrl.Dereference() + else: + self.cntrl = None + +# we can use two different categories for old and new formatters - type names are different enough that we should make no confusion +# talking with libc++ developer: "std::__1::class_name is set in stone +# until we decide to change the ABI. That shouldn't happen within a 5 year +# time frame" + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx') + debugger.HandleCommand( + 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string, class std::__1::allocator >" -w libcxx') + debugger.HandleCommand( + 'type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx') + debugger.HandleCommand( + 'type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx') + debugger.HandleCommand( + 'type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx') + debugger.HandleCommand( + 'type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx') + debugger.HandleCommand( + 'type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx') + debugger.HandleCommand( + 'type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx') + debugger.HandleCommand("type category enable libcxx") + debugger.HandleCommand( + 'type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx') + debugger.HandleCommand( + 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx') + # turns out the structs look the same, so weak_ptr can be handled the same! + debugger.HandleCommand( + 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx') + +_map_capping_size = 255 +_list_capping_size = 255 +_list_uses_loop_detector = True +_deque_capping_size = 255 diff --git a/examples/synthetic/unordered_multi.py b/examples/synthetic/unordered_multi.py new file mode 100644 index 000000000..da7ba456a --- /dev/null +++ b/examples/synthetic/unordered_multi.py @@ -0,0 +1,124 @@ +import lldb + +_map_capping_size = 255 + + +class libcxx_hash_table_SynthProvider: + + def __init__(self, valobj, dict): + self.valobj = valobj + self.num_elements = None + self.next_element = None + self.bucket_count = None + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.num_elements = None + self.next_element = None + self.bucket_count = None + try: + # unordered_map is made up of a hash_map, which has 4 pieces in it: + # bucket list : + # array of buckets + # p1 (pair): + # first - pointer to first loaded element + # p2 (pair): + # first - number of elements + # second - hash function + # p3 (pair): + # first - max_load_factor + # second - equality operator function + # + # For display, we actually don't need to go inside the buckets, since 'p1' has a way to iterate over all + # the elements directly. + # + # We will calculate other values about the map because they will be useful for the summary. + # + table = self.valobj.GetChildMemberWithName('__table_') + + bl_ptr = table.GetChildMemberWithName( + '__bucket_list_').GetChildMemberWithName('__ptr_') + self.bucket_array_ptr = bl_ptr.GetChildMemberWithName( + '__first_').GetValueAsUnsigned(0) + self.bucket_count = bl_ptr.GetChildMemberWithName('__second_').GetChildMemberWithName( + '__data_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + logger >> "Bucket count = %r" % self.bucket_count + + self.begin_ptr = table.GetChildMemberWithName('__p1_').GetChildMemberWithName( + '__first_').GetChildMemberWithName('__next_') + + self.num_elements = table.GetChildMemberWithName( + '__p2_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + self.max_load_factor = table.GetChildMemberWithName( + '__p3_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + logger >> "Num elements = %r" % self.num_elements + + # save the pointers as we get them + # -- don't access this first element if num_element==0! + self.elements_cache = [] + if self.num_elements: + self.next_element = self.begin_ptr + else: + self.next_element = None + except Exception as e: + logger >> "Caught exception: %r" % e + pass + + def num_children(self): + global _map_capping_size + num_elements = self.num_elements + if num_elements is not None: + if num_elements > _map_capping_size: + num_elements = _map_capping_size + return num_elements + + def has_children(self): + return True + + def get_child_index(self, name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self, index): + logger = lldb.formatters.Logger.Logger() + logger >> "Retrieving child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None + + # extend + logger >> " : cache size starts with %d elements" % len( + self.elements_cache) + while index >= len(self.elements_cache): + # if we hit the end before we get the index, give up: + if not self.next_element: + logger >> " : hit end of list" + return None + + node = self.next_element.Dereference() + + value = node.GetChildMemberWithName('__value_') + hash_value = node.GetChildMemberWithName( + '__hash_').GetValueAsUnsigned() + self.elements_cache.append((value, hash_value)) + + self.next_element = node.GetChildMemberWithName('__next_') + if not self.next_element.GetValueAsUnsigned(0): + self.next_element = None + + # hit the index! so we have the value + logger >> " : cache size ends with %d elements" % len( + self.elements_cache) + value, hash_value = self.elements_cache[index] + return self.valobj.CreateValueFromData( + '[%d] ' % + (index, hash_value), value.GetData(), value.GetType()) + + +def __lldb_init_module(debugger, dict): + debugger.HandleCommand( + 'type synthetic add -l unordered_multi.libcxx_hash_table_SynthProvider -x "^(std::__1::)unordered_(multi)?(map|set)<.+> >$" -w libcxx') diff --git a/examples/test/.lldb-loggings b/examples/test/.lldb-loggings new file mode 100644 index 000000000..9c92bd958 --- /dev/null +++ b/examples/test/.lldb-loggings @@ -0,0 +1,20 @@ +def pre_flight(self): + import os + import lldb + import lldbtest + + dname = os.path.join(os.environ["LLDB_TEST"], + os.environ["LLDB_SESSION_DIRNAME"]) + if not os.path.isdir(dname): + os.mkdir(dname) + dest = os.path.join(dname, "lldb_log-%s-%s-%s.txt" % (self.getArchitecture(), self.getCompiler(), self.id())) + print "\nEnabling lldb logging for test case:", self + print "with log destination:", dest + self.runCmd("log enable -f %s gdb-remote packets process" % dest) + +#def post_flight(test): +# __import__("lldb") +# __import__("lldbtest") +# print "\nRunning post-flight function:" +# print "for test case:", test + diff --git a/examples/test/.lldb-pre-post-flight b/examples/test/.lldb-pre-post-flight new file mode 100644 index 000000000..c1568a729 --- /dev/null +++ b/examples/test/.lldb-pre-post-flight @@ -0,0 +1,12 @@ +def pre_flight(test): + __import__("lldb") + __import__("lldbtest") + print "\nRunning pre-flight function:" + print "for test case:", test + +def post_flight(test): + __import__("lldb") + __import__("lldbtest") + print "\nRunning post-flight function:" + print "for test case:", test + diff --git a/examples/test/.lldb-pre-post-flight.bad b/examples/test/.lldb-pre-post-flight.bad new file mode 100644 index 000000000..0e17f3cdc --- /dev/null +++ b/examples/test/.lldb-pre-post-flight.bad @@ -0,0 +1,8 @@ +pre_flight = "I am not callable" + +def post_flight(test): + __import__("lldb") + __import__("lldbtest") + print "\nRunning post-flight function:" + print "for test case:", test + diff --git a/examples/test/.lldbtest-config b/examples/test/.lldbtest-config new file mode 100644 index 000000000..31b489207 --- /dev/null +++ b/examples/test/.lldbtest-config @@ -0,0 +1,6 @@ +sys.stderr = open("/tmp/lldbtest-stderr", "w") +sys.stdout = open("/tmp/lldbtest-stdout", "w") +compilers = ["gcc", "llvm-gcc"] +archs = ["x86_64", "i386"] +split_stderr = True # This will split the stderr into configuration-specific file +split_stdout = True # This will split the stdout into configuration-specific file diff --git a/examples/test/.lldbtest-config2 b/examples/test/.lldbtest-config2 new file mode 100644 index 000000000..bf44726fd --- /dev/null +++ b/examples/test/.lldbtest-config2 @@ -0,0 +1,19 @@ +# Example config file for running the test suite for both 64 and 32-bit +# architectures. +# +# I use the following command to invoke the test driver: +# +# /Volumes/data/lldb/svn/trunk/test $ ./dotest.py -r /Volumes/data/lldb-test/archs -s session -c ../examples/test/.lldbtest-config2 -v -w . 2> ~/Developer/Log/lldbtest.log +# +# The '-r' option tells the driver to relocate the test execution to +# /Volumes/data/lldb-test/archs which must not exist before the run. +# +# Test failures/errors will be recorded into the 'session' directory due to the +# '-s' option, e.g., /Volumes/data/lldb-test/archs.arch=i386/test/session could +# contain the following three session info files: +# +# -rw-r--r-- 1 johnny admin 1737 Oct 25 13:25 TestArrayTypes.ArrayTypesTestCase.test_with_dwarf_and_run_command.log +# -rw-r--r-- 1 johnny admin 1733 Oct 25 13:25 TestClassTypes.ClassTypesTestCase.test_with_dwarf_and_run_command.log +# -rw-r--r-- 1 johnny admin 4677 Oct 25 13:26 TestObjCMethods.FoundationTestCase.test_data_type_and_expr_with_dsym.log + +archs = ["x86_64", "i386"] diff --git a/examples/test/lldbtest-stderr b/examples/test/lldbtest-stderr new file mode 100644 index 000000000..7934d9283 --- /dev/null +++ b/examples/test/lldbtest-stderr @@ -0,0 +1,39 @@ +---------------------------------------------------------------------- +Collected 1 test + + +Configuration: arch=x86_64 compiler=gcc +test_persistent_variables (TestPersistentVariables.PersistentVariablesTestCase) +Test that lldb persistent variables works correctly. ... ok + +---------------------------------------------------------------------- +Ran 1 test in 1.397s + +OK + +Configuration: arch=x86_64 compiler=llvm-gcc +test_persistent_variables (TestPersistentVariables.PersistentVariablesTestCase) +Test that lldb persistent variables works correctly. ... ok + +---------------------------------------------------------------------- +Ran 1 test in 1.282s + +OK + +Configuration: arch=i386 compiler=gcc +test_persistent_variables (TestPersistentVariables.PersistentVariablesTestCase) +Test that lldb persistent variables works correctly. ... ok + +---------------------------------------------------------------------- +Ran 1 test in 1.297s + +OK + +Configuration: arch=i386 compiler=llvm-gcc +test_persistent_variables (TestPersistentVariables.PersistentVariablesTestCase) +Test that lldb persistent variables works correctly. ... ok + +---------------------------------------------------------------------- +Ran 1 test in 1.269s + +OK diff --git a/examples/test/lldbtest-stdout b/examples/test/lldbtest-stdout new file mode 100644 index 000000000..e69de29bb diff --git a/examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt b/examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt new file mode 100644 index 000000000..c1448cd84 --- /dev/null +++ b/examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt @@ -0,0 +1,55 @@ +com.apple.main-thread /Volumes/data/lldb/svn/ToT/build/Debug/LLDB.framework/Versions/A/Resources/debugserver arguments: +argv[0]="/Volumes/data/lldb/svn/ToT/build/Debug/LLDB.framework/Versions/A/Resources/debugserver" +argv[1]="localhost:14953" +argv[2]="--native-regs" +argv[3]="--setsid" +argv[4]=NULL + + +com.apple.main-thread Host::LaunchProcess (launch_info) => pid=55237, path='/Volumes/data/lldb/svn/ToT/build/Debug/LLDB.framework/Versions/A/Resources/debugserver' err = 0x00000000 +com.apple.main-thread ProcessGDBRemote::StartAsyncThread () + ProcessGDBRemote::AsyncThread (arg = 0x7fabc1883400, pid = 0) thread starting... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc1883400, pid = 0) listener.WaitForEvent (NULL, event_sp)... +com.apple.main-thread < 1> send packet: + +com.apple.main-thread history[1] tid=0x1307 < 1> send packet: + +com.apple.main-thread < 19> send packet: $QStartNoAckMode#b0 +com.apple.main-thread < 1> read packet: + +com.apple.main-thread < 6> read packet: $OK#9a +com.apple.main-thread < 1> send packet: + +com.apple.main-thread < 26> send packet: $QThreadSuffixSupported#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 27> send packet: $QListThreadsInStopReply#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 13> send packet: $qHostInfo#00 +com.apple.main-thread < 122> read packet: $cputype:16777223;cpusubtype:3;ostype:macosx;watchpoint_exceptions_received:after;vendor:apple;endian:little;ptrsize:8;#00 +com.apple.main-thread < 10> send packet: $vCont?#00 +com.apple.main-thread < 17> read packet: $vCont;c;C;s;S#00 +com.apple.main-thread < 27> send packet: $qVAttachOrWaitSupported#00 +com.apple.main-thread < 6> read packet: $OK#00 + +... + +com.apple.main-thread ProcessGDBRemote::DoDestroy() +com.apple.main-thread < 5> send packet: $k#00 +com.apple.main-thread error: failed to get response for 'k' +com.apple.main-thread ProcessGDBRemote::DoDestroy - failed to send k packet +com.apple.main-thread ProcessGDBRemote::StopAsyncThread () + ProcessGDBRemote::AsyncThread (arg = 0x7fabc185e200, pid = 55239) Got an event of type: 2... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc185e200, pid = 55239) got eBroadcastBitAsyncThreadShouldExit... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc185e200, pid = 55239) thread exiting... +com.apple.root.default-priority ProcessGDBRemote::MonitorDebugserverProcess (baton=0x7fabc185e200, pid=55240, signo=2 (0x2), exit_status=-1) +com.apple.main-thread < 18> send packet: $z0,100000e37,1#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 21> send packet: $z0,7fff5fc0d6e5,1#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 21> send packet: $z0,7fff8b132187,1#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread ProcessGDBRemote::DoDestroy() +com.apple.main-thread < 5> send packet: $k#00 +com.apple.main-thread error: failed to get response for 'k' +com.apple.main-thread ProcessGDBRemote::DoDestroy - failed to send k packet +com.apple.main-thread ProcessGDBRemote::StopAsyncThread () + ProcessGDBRemote::AsyncThread (arg = 0x7fabc18f8600, pid = 55243) Got an event of type: 2... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc18f8600, pid = 55243) got eBroadcastBitAsyncThreadShouldExit... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc18f8600, pid = 55243) thread exiting... +com.apple.root.default-priority ProcessGDBRemote::MonitorDebugserverProcess (baton=0x7fabc18f8600, pid=55244, signo=2 (0x2), exit_status=-1) diff --git a/examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt b/examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt new file mode 100644 index 000000000..87cfddb29 --- /dev/null +++ b/examples/test/tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt @@ -0,0 +1,55 @@ +com.apple.main-thread /Volumes/data/lldb/svn/ToT/build/Debug/LLDB.framework/Versions/A/Resources/debugserver arguments: +argv[0]="/Volumes/data/lldb/svn/ToT/build/Debug/LLDB.framework/Versions/A/Resources/debugserver" +argv[1]="localhost:33231" +argv[2]="--native-regs" +argv[3]="--setsid" +argv[4]=NULL + + +com.apple.main-thread Host::LaunchProcess (launch_info) => pid=55287, path='/Volumes/data/lldb/svn/ToT/build/Debug/LLDB.framework/Versions/A/Resources/debugserver' err = 0x00000000 +com.apple.main-thread ProcessGDBRemote::StartAsyncThread () + ProcessGDBRemote::AsyncThread (arg = 0x7fabc0997600, pid = 0) thread starting... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc0997600, pid = 0) listener.WaitForEvent (NULL, event_sp)... +com.apple.main-thread < 1> send packet: + +com.apple.main-thread history[1] tid=0x1307 < 1> send packet: + +com.apple.main-thread < 19> send packet: $QStartNoAckMode#b0 +com.apple.main-thread < 1> read packet: + +com.apple.main-thread < 6> read packet: $OK#9a +com.apple.main-thread < 1> send packet: + +com.apple.main-thread < 26> send packet: $QThreadSuffixSupported#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 27> send packet: $QListThreadsInStopReply#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 13> send packet: $qHostInfo#00 +com.apple.main-thread < 122> read packet: $cputype:16777223;cpusubtype:3;ostype:macosx;watchpoint_exceptions_received:after;vendor:apple;endian:little;ptrsize:8;#00 +com.apple.main-thread < 10> send packet: $vCont?#00 +com.apple.main-thread < 17> read packet: $vCont;c;C;s;S#00 +com.apple.main-thread < 27> send packet: $qVAttachOrWaitSupported#00 +com.apple.main-thread < 6> read packet: $OK#00 + +... + +com.apple.main-thread ProcessGDBRemote::DoDestroy() +com.apple.main-thread < 5> send packet: $k#00 +com.apple.main-thread error: failed to get response for 'k' +com.apple.main-thread ProcessGDBRemote::DoDestroy - failed to send k packet +com.apple.main-thread ProcessGDBRemote::StopAsyncThread () + ProcessGDBRemote::AsyncThread (arg = 0x7fabc1882000, pid = 55289) Got an event of type: 2... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc1882000, pid = 55289) got eBroadcastBitAsyncThreadShouldExit... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc1882000, pid = 55289) thread exiting... +com.apple.root.default-priority ProcessGDBRemote::MonitorDebugserverProcess (baton=0x7fabc1882000, pid=55290, signo=2 (0x2), exit_status=-1) +com.apple.main-thread < 18> send packet: $z0,100000e37,1#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 21> send packet: $z0,7fff5fc0d6e5,1#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread < 21> send packet: $z0,7fff8b132187,1#00 +com.apple.main-thread < 6> read packet: $OK#00 +com.apple.main-thread ProcessGDBRemote::DoDestroy() +com.apple.main-thread < 5> send packet: $k#00 +com.apple.main-thread error: failed to get response for 'k' +com.apple.main-thread ProcessGDBRemote::DoDestroy - failed to send k packet +com.apple.main-thread ProcessGDBRemote::StopAsyncThread () + ProcessGDBRemote::AsyncThread (arg = 0x7fabc0bed200, pid = 55292) Got an event of type: 2... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc0bed200, pid = 55292) got eBroadcastBitAsyncThreadShouldExit... + ProcessGDBRemote::AsyncThread (arg = 0x7fabc0bed200, pid = 55292) thread exiting... +com.apple.root.default-priority ProcessGDBRemote::MonitorDebugserverProcess (baton=0x7fabc0bed200, pid=55293, signo=2 (0x2), exit_status=-1) diff --git a/examples/test/usage-config b/examples/test/usage-config new file mode 100644 index 000000000..4f3d3b222 --- /dev/null +++ b/examples/test/usage-config @@ -0,0 +1,10 @@ +# This is an example of using the "-c" option to source a config file to +# reassign the system stderr and stdout and to exercise different combinations +# of architectures and compilers. +# +# The config file is checked in as .lldbtest-config and the redirected stderr +# and stdout are checked in as lldbtest-stderr and lldbtest-stdout, all in the +# the same directory as this file. + +[15:36:32] johnny:/Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v -c ~/.lldbtest-config persistent_variables +[15:40:55] johnny:/Volumes/data/lldb/svn/trunk/test $ diff --git a/examples/test/usage-lldb-loggings b/examples/test/usage-lldb-loggings new file mode 100644 index 000000000..b7d7e2e58 --- /dev/null +++ b/examples/test/usage-lldb-loggings @@ -0,0 +1,125 @@ +# +# The following example shows how to utilize the pre-flight config file to route the lldb gdb-remote log messages +# into individual log destinations. +# +# See also .lldb-loggings in this directory as well as the tmp dir which contains the two log files abridged due +# to their log sizes. +# + +[11:31:34] johnny:/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-loggings functionalities/breakpoint/breakpoint_command +config: {'pre_flight': } +LLDB build dir: /Volumes/data/lldb/svn/ToT/build/Debug +LLDB-165 +Path: /Volumes/data/lldb/svn/ToT +URL: https://johnny@llvm.org/svn/llvm-project/lldb/trunk +Repository Root: https://johnny@llvm.org/svn/llvm-project +Repository UUID: 91177308-0d34-0410-b5e6-96231b3b80d8 +Revision: 162231 +Node Kind: directory +Schedule: normal +Last Changed Author: johnny +Last Changed Rev: 162228 +Last Changed Date: 2012-08-20 14:16:02 -0700 (Mon, 20 Aug 2012) + + +lldb.pre_flight: def pre_flight(self): + import os + import lldb + import lldbtest + + dest = os.path.join("/tmp", "lldb_log-%s-%s-%s.txt" % (self.getArchitecture(), self.getCompiler(), self.id())) + print "\nEnabling lldb logging for test case:", self + print "with log destination:", dest + self.runCmd("log enable -f %s gdb-remote packets process" % dest) + +lldb.post_flight: None + +Session logs for test failures/errors/unexpected successes will go into directory '2012-08-22-11_36_37' +Command invoked: python ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-loggings functionalities/breakpoint/breakpoint_command +compilers=['clang'] + +Configuration: arch=x86_64 compiler=clang +---------------------------------------------------------------------- +Collected 2 tests + +1: test_with_dsym (TestBreakpointCommand.BreakpointCommandTestCase) + Test a sequence of breakpoint command add, list, and delete. ... +Enabling lldb logging for test case: test_with_dsym (TestBreakpointCommand.BreakpointCommandTestCase) +with log destination: /tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt +ok +2: test_with_dwarf (TestBreakpointCommand.BreakpointCommandTestCase) + Test a sequence of breakpoint command add, list, and delete. ... +Enabling lldb logging for test case: test_with_dwarf (TestBreakpointCommand.BreakpointCommandTestCase) +with log destination: /tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt +ok + +---------------------------------------------------------------------- +Ran 2 tests in 7.826s + +OK +[11:36:44] johnny:/Volumes/data/lldb/svn/ToT/test $ ls -l /tmp/lldb_log* +-rw-r----- 1 johnny wheel 614614 Aug 22 11:36 /tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt +-rw-r----- 1 johnny wheel 614614 Aug 22 11:36 /tmp/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt +[11:37:09] johnny:/Volumes/data/lldb/svn/ToT/test $ + +# +# And this shows the log files go into the session directory. +# Note that the .lldb-loggings file is modified to get the session directory now. +# + +[11:37:09] johnny:/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-loggings functionalities/breakpoint/breakpoint_command +config: {'pre_flight': } +LLDB build dir: /Volumes/data/lldb/svn/ToT/build/Debug +LLDB-165 +Path: /Volumes/data/lldb/svn/ToT +URL: https://johnny@llvm.org/svn/llvm-project/lldb/trunk +Repository Root: https://johnny@llvm.org/svn/llvm-project +Repository UUID: 91177308-0d34-0410-b5e6-96231b3b80d8 +Revision: 162231 +Node Kind: directory +Schedule: normal +Last Changed Author: johnny +Last Changed Rev: 162228 +Last Changed Date: 2012-08-20 14:16:02 -0700 (Mon, 20 Aug 2012) + + +lldb.pre_flight: def pre_flight(self): + import os + import lldb + import lldbtest + + dname = os.path.join(os.environ["LLDB_TEST"], + os.environ["LLDB_SESSION_DIRNAME"]) + if not os.path.isdir(dname): + os.mkdir(dname) + dest = os.path.join(dname, "lldb_log-%s-%s-%s.txt" % (self.getArchitecture(), self.getCompiler(), self.id())) + print "\nEnabling lldb logging for test case:", self + print "with log destination:", dest + self.runCmd("log enable -f %s gdb-remote packets process" % dest) + +lldb.post_flight: None + +Session logs for test failures/errors/unexpected successes will go into directory '2012-08-22-13_21_46' +Command invoked: python ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-loggings functionalities/breakpoint/breakpoint_command +compilers=['clang'] + +Configuration: arch=x86_64 compiler=clang +---------------------------------------------------------------------- +Collected 2 tests + +1: test_with_dsym (TestBreakpointCommand.BreakpointCommandTestCase) + Test a sequence of breakpoint command add, list, and delete. ... +Enabling lldb logging for test case: test_with_dsym (TestBreakpointCommand.BreakpointCommandTestCase) +with log destination: /Volumes/data/lldb/svn/ToT/test/2012-08-22-13_21_46/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dsym.txt +ok +2: test_with_dwarf (TestBreakpointCommand.BreakpointCommandTestCase) + Test a sequence of breakpoint command add, list, and delete. ... +Enabling lldb logging for test case: test_with_dwarf (TestBreakpointCommand.BreakpointCommandTestCase) +with log destination: /Volumes/data/lldb/svn/ToT/test/2012-08-22-13_21_46/lldb_log-x86_64-clang-TestBreakpointCommand.BreakpointCommandTestCase.test_with_dwarf.txt +ok + +---------------------------------------------------------------------- +Ran 2 tests in 8.575s + +OK +[13:21:55] johnny:/Volumes/data/lldb/svn/ToT/test $ diff --git a/examples/test/usage-pre-post-flight b/examples/test/usage-pre-post-flight new file mode 100644 index 000000000..da6860724 --- /dev/null +++ b/examples/test/usage-pre-post-flight @@ -0,0 +1,65 @@ +# +# The following examples first show a bad pre/post flight config file followed by a good pre/post config file. +# + +[11:31:19] johnny:/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-pre-post-flight.bad functionalities/watchpoint/hello_watchpoint +config: {'pre_flight': 'I am not callable', 'post_flight': } +fatal error: pre_flight is not callable, exiting. +[11:32:48] johnny:/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-pre-post-flight functionalities/watchpoint/hello_watchpoint +config: {'pre_flight': , 'post_flight': } +LLDB build dir: /Volumes/data/lldb/svn/ToT/build/Debug +LLDB-139 +Path: /Volumes/data/lldb/svn/ToT +URL: https://johnny@llvm.org/svn/llvm-project/lldb/trunk +Repository Root: https://johnny@llvm.org/svn/llvm-project +Repository UUID: 91177308-0d34-0410-b5e6-96231b3b80d8 +Revision: 154753 +Node Kind: directory +Schedule: normal +Last Changed Author: gclayton +Last Changed Rev: 154730 +Last Changed Date: 2012-04-13 18:42:46 -0700 (Fri, 13 Apr 2012) + + +lldb.pre_flight: def pre_flight(test): + __import__("lldb") + __import__("lldbtest") + print "\nRunning pre-flight function:" + print "for test case:", test + +lldb.post_flight: def post_flight(test): + __import__("lldb") + __import__("lldbtest") + print "\nRunning post-flight function:" + print "for test case:", test + + +Session logs for test failures/errors/unexpected successes will go into directory '2012-04-16-11_34_08' +Command invoked: python ./dotest.py -A x86_64 -v -c ../examples/test/.lldb-pre-post-flight functionalities/watchpoint/hello_watchpoint +compilers=['clang'] + +Configuration: arch=x86_64 compiler=clang +---------------------------------------------------------------------- +Collected 2 tests + +1: test_hello_watchpoint_with_dsym_using_watchpoint_set (TestMyFirstWatchpoint.HelloWatchpointTestCase) + Test a simple sequence of watchpoint creation and watchpoint hit. ... +Running pre-flight function: +for test case: test_hello_watchpoint_with_dsym_using_watchpoint_set (TestMyFirstWatchpoint.HelloWatchpointTestCase) + +Running post-flight function: +for test case: test_hello_watchpoint_with_dsym_using_watchpoint_set (TestMyFirstWatchpoint.HelloWatchpointTestCase) +ok +2: test_hello_watchpoint_with_dwarf_using_watchpoint_set (TestMyFirstWatchpoint.HelloWatchpointTestCase) + Test a simple sequence of watchpoint creation and watchpoint hit. ... +Running pre-flight function: +for test case: test_hello_watchpoint_with_dwarf_using_watchpoint_set (TestMyFirstWatchpoint.HelloWatchpointTestCase) + +Running post-flight function: +for test case: test_hello_watchpoint_with_dwarf_using_watchpoint_set (TestMyFirstWatchpoint.HelloWatchpointTestCase) +ok + +---------------------------------------------------------------------- +Ran 2 tests in 1.584s + +OK \ No newline at end of file diff --git a/include/lldb/API/LLDB.h b/include/lldb/API/LLDB.h new file mode 100644 index 000000000..cf61b1018 --- /dev/null +++ b/include/lldb/API/LLDB.h @@ -0,0 +1,82 @@ +//===-- LLDB.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_LLDB_h_ +#define LLDB_LLDB_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBAttachInfo.h" +#include "lldb/API/SBBlock.h" +#include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBBroadcaster.h" +#include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandReturnObject.h" +#include "lldb/API/SBCommunication.h" +#include "lldb/API/SBCompileUnit.h" +#include "lldb/API/SBData.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBDeclaration.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBEvent.h" +#include "lldb/API/SBExecutionContext.h" +#include "lldb/API/SBExpressionOptions.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBFileSpecList.h" +#include "lldb/API/SBFrame.h" +#include "lldb/API/SBFunction.h" +#include "lldb/API/SBHostOS.h" +#include "lldb/API/SBInstruction.h" +#include "lldb/API/SBInstructionList.h" +#include "lldb/API/SBLanguageRuntime.h" +#include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBLineEntry.h" +#include "lldb/API/SBListener.h" +#include "lldb/API/SBMemoryRegionInfo.h" +#include "lldb/API/SBMemoryRegionInfoList.h" +#include "lldb/API/SBModule.h" +#include "lldb/API/SBModuleSpec.h" +#include "lldb/API/SBPlatform.h" +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBQueue.h" +#include "lldb/API/SBQueueItem.h" +#include "lldb/API/SBSection.h" +#include "lldb/API/SBSourceManager.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBStringList.h" +#include "lldb/API/SBStructuredData.h" +#include "lldb/API/SBSymbol.h" +#include "lldb/API/SBSymbolContext.h" +#include "lldb/API/SBSymbolContextList.h" +#include "lldb/API/SBTarget.h" +#include "lldb/API/SBThread.h" +#include "lldb/API/SBThreadCollection.h" +#include "lldb/API/SBThreadPlan.h" +#include "lldb/API/SBTrace.h" +#include "lldb/API/SBTraceOptions.h" +#include "lldb/API/SBType.h" +#include "lldb/API/SBTypeCategory.h" +#include "lldb/API/SBTypeEnumMember.h" +#include "lldb/API/SBTypeFilter.h" +#include "lldb/API/SBTypeFormat.h" +#include "lldb/API/SBTypeNameSpecifier.h" +#include "lldb/API/SBTypeSummary.h" +#include "lldb/API/SBTypeSynthetic.h" +#include "lldb/API/SBUnixSignals.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBValueList.h" +#include "lldb/API/SBVariablesOptions.h" +#include "lldb/API/SBWatchpoint.h" + +#endif // LLDB_LLDB_h_ diff --git a/include/lldb/API/SBAddress.h b/include/lldb/API/SBAddress.h new file mode 100644 index 000000000..9e697beff --- /dev/null +++ b/include/lldb/API/SBAddress.h @@ -0,0 +1,126 @@ +//===-- SBAddress.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBAddress_h_ +#define LLDB_SBAddress_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBModule.h" + +namespace lldb { + +class LLDB_API SBAddress { +public: + SBAddress(); + + SBAddress(const lldb::SBAddress &rhs); + + SBAddress(lldb::SBSection section, lldb::addr_t offset); + + // Create an address by resolving a load address using the supplied target + SBAddress(lldb::addr_t load_addr, lldb::SBTarget &target); + + ~SBAddress(); + + const lldb::SBAddress &operator=(const lldb::SBAddress &rhs); + + bool IsValid() const; + + void Clear(); + + addr_t GetFileAddress() const; + + addr_t GetLoadAddress(const lldb::SBTarget &target) const; + + void SetAddress(lldb::SBSection section, lldb::addr_t offset); + + void SetLoadAddress(lldb::addr_t load_addr, lldb::SBTarget &target); + bool OffsetAddress(addr_t offset); + + bool GetDescription(lldb::SBStream &description); + + // The following queries can lookup symbol information for a given address. + // An address might refer to code or data from an existing module, or it + // might refer to something on the stack or heap. The following functions + // will only return valid values if the address has been resolved to a code + // or data address using "void SBAddress::SetLoadAddress(...)" or + // "lldb::SBAddress SBTarget::ResolveLoadAddress (...)". + lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope); + + // The following functions grab individual objects for a given address and + // are less efficient if you want more than one symbol related objects. + // Use one of the following when you want multiple debug symbol related + // objects for an address: + // lldb::SBSymbolContext SBAddress::GetSymbolContext (uint32_t + // resolve_scope); + // lldb::SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const + // SBAddress &addr, uint32_t resolve_scope); + // One or more bits from the SymbolContextItem enumerations can be logically + // OR'ed together to more efficiently retrieve multiple symbol objects. + + lldb::SBSection GetSection(); + + lldb::addr_t GetOffset(); + + lldb::SBModule GetModule(); + + lldb::SBCompileUnit GetCompileUnit(); + + lldb::SBFunction GetFunction(); + + lldb::SBBlock GetBlock(); + + lldb::SBSymbol GetSymbol(); + + lldb::SBLineEntry GetLineEntry(); + + lldb::AddressClass GetAddressClass(); + +protected: + friend class SBBlock; + friend class SBBreakpointLocation; + friend class SBFrame; + friend class SBFunction; + friend class SBLineEntry; + friend class SBInstruction; + friend class SBModule; + friend class SBSection; + friend class SBSymbol; + friend class SBSymbolContext; + friend class SBTarget; + friend class SBThread; + friend class SBThreadPlan; + friend class SBValue; + friend class SBQueueItem; + + lldb_private::Address *operator->(); + + const lldb_private::Address *operator->() const; + + friend bool operator==(const SBAddress &lhs, const SBAddress &rhs); + + lldb_private::Address *get(); + + lldb_private::Address &ref(); + + const lldb_private::Address &ref() const; + + SBAddress(const lldb_private::Address *lldb_object_ptr); + + void SetAddress(const lldb_private::Address *lldb_object_ptr); + +private: + std::unique_ptr m_opaque_ap; +}; + +bool operator==(const SBAddress &lhs, const SBAddress &rhs); + +} // namespace lldb + +#endif // LLDB_SBAddress_h_ diff --git a/include/lldb/API/SBAttachInfo.h b/include/lldb/API/SBAttachInfo.h new file mode 100644 index 000000000..7ae006908 --- /dev/null +++ b/include/lldb/API/SBAttachInfo.h @@ -0,0 +1,190 @@ +//===-- SBAttachInfo.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBAttachInfo_h_ +#define LLDB_SBAttachInfo_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class SBTarget; + +class LLDB_API SBAttachInfo { +public: + SBAttachInfo(); + + SBAttachInfo(lldb::pid_t pid); + + //------------------------------------------------------------------ + /// Attach to a process by name. + /// + /// This function implies that a future call to SBTarget::Attach(...) + /// will be synchronous. + /// + /// @param[in] path + /// A full or partial name for the process to attach to. + /// + /// @param[in] wait_for + /// If \b false, attach to an existing process whose name matches. + /// If \b true, then wait for the next process whose name matches. + //------------------------------------------------------------------ + SBAttachInfo(const char *path, bool wait_for); + + //------------------------------------------------------------------ + /// Attach to a process by name. + /// + /// Future calls to SBTarget::Attach(...) will be synchronous or + /// asynchronous depending on the \a async argument. + /// + /// @param[in] path + /// A full or partial name for the process to attach to. + /// + /// @param[in] wait_for + /// If \b false, attach to an existing process whose name matches. + /// If \b true, then wait for the next process whose name matches. + /// + /// @param[in] async + /// If \b false, then the SBTarget::Attach(...) call will be a + /// synchronous call with no way to cancel the attach in + /// progress. + /// If \b true, then the SBTarget::Attach(...) function will + /// return immediately and clients are expected to wait for a + /// process eStateStopped event if a suitable process is + /// eventually found. If the client wants to cancel the event, + /// SBProcess::Stop() can be called and an eStateExited process + /// event will be delivered. + //------------------------------------------------------------------ + SBAttachInfo(const char *path, bool wait_for, bool async); + + SBAttachInfo(const SBAttachInfo &rhs); + + ~SBAttachInfo(); + + SBAttachInfo &operator=(const SBAttachInfo &rhs); + + lldb::pid_t GetProcessID(); + + void SetProcessID(lldb::pid_t pid); + + void SetExecutable(const char *path); + + void SetExecutable(lldb::SBFileSpec exe_file); + + bool GetWaitForLaunch(); + + //------------------------------------------------------------------ + /// Set attach by process name settings. + /// + /// Designed to be used after a call to SBAttachInfo::SetExecutable(). + /// This function implies that a call to SBTarget::Attach(...) will + /// be synchronous. + /// + /// @param[in] b + /// If \b false, attach to an existing process whose name matches. + /// If \b true, then wait for the next process whose name matches. + //------------------------------------------------------------------ + void SetWaitForLaunch(bool b); + + //------------------------------------------------------------------ + /// Set attach by process name settings. + /// + /// Designed to be used after a call to SBAttachInfo::SetExecutable(). + /// Future calls to SBTarget::Attach(...) will be synchronous or + /// asynchronous depending on the \a async argument. + /// + /// @param[in] b + /// If \b false, attach to an existing process whose name matches. + /// If \b true, then wait for the next process whose name matches. + /// + /// @param[in] async + /// If \b false, then the SBTarget::Attach(...) call will be a + /// synchronous call with no way to cancel the attach in + /// progress. + /// If \b true, then the SBTarget::Attach(...) function will + /// return immediately and clients are expected to wait for a + /// process eStateStopped event if a suitable process is + /// eventually found. If the client wants to cancel the event, + /// SBProcess::Stop() can be called and an eStateExited process + /// event will be delivered. + //------------------------------------------------------------------ + void SetWaitForLaunch(bool b, bool async); + + bool GetIgnoreExisting(); + + void SetIgnoreExisting(bool b); + + uint32_t GetResumeCount(); + + void SetResumeCount(uint32_t c); + + const char *GetProcessPluginName(); + + void SetProcessPluginName(const char *plugin_name); + + uint32_t GetUserID(); + + uint32_t GetGroupID(); + + bool UserIDIsValid(); + + bool GroupIDIsValid(); + + void SetUserID(uint32_t uid); + + void SetGroupID(uint32_t gid); + + uint32_t GetEffectiveUserID(); + + uint32_t GetEffectiveGroupID(); + + bool EffectiveUserIDIsValid(); + + bool EffectiveGroupIDIsValid(); + + void SetEffectiveUserID(uint32_t uid); + + void SetEffectiveGroupID(uint32_t gid); + + lldb::pid_t GetParentProcessID(); + + void SetParentProcessID(lldb::pid_t pid); + + bool ParentProcessIDIsValid(); + + //---------------------------------------------------------------------- + /// Get the listener that will be used to receive process events. + /// + /// If no listener has been set via a call to + /// SBAttachInfo::SetListener(), then an invalid SBListener will be + /// returned (SBListener::IsValid() will return false). If a listener + /// has been set, then the valid listener object will be returned. + //---------------------------------------------------------------------- + SBListener GetListener(); + + //---------------------------------------------------------------------- + /// Set the listener that will be used to receive process events. + /// + /// By default the SBDebugger, which has a listener, that the SBTarget + /// belongs to will listen for the process events. Calling this function + /// allows a different listener to be used to listen for process events. + //---------------------------------------------------------------------- + void SetListener(SBListener &listener); + +protected: + friend class SBTarget; + + lldb_private::ProcessAttachInfo &ref(); + + ProcessAttachInfoSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBAttachInfo_h_ diff --git a/include/lldb/API/SBBlock.h b/include/lldb/API/SBBlock.h new file mode 100644 index 000000000..112de9673 --- /dev/null +++ b/include/lldb/API/SBBlock.h @@ -0,0 +1,96 @@ +//===-- SBBlock.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBBlock_h_ +#define LLDB_SBBlock_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFrame.h" +#include "lldb/API/SBTarget.h" +#include "lldb/API/SBValueList.h" + +namespace lldb { + +class LLDB_API SBBlock { +public: + SBBlock(); + + SBBlock(const lldb::SBBlock &rhs); + + ~SBBlock(); + + const lldb::SBBlock &operator=(const lldb::SBBlock &rhs); + + bool IsInlined() const; + + bool IsValid() const; + + const char *GetInlinedName() const; + + lldb::SBFileSpec GetInlinedCallSiteFile() const; + + uint32_t GetInlinedCallSiteLine() const; + + uint32_t GetInlinedCallSiteColumn() const; + + lldb::SBBlock GetParent(); + + lldb::SBBlock GetSibling(); + + lldb::SBBlock GetFirstChild(); + + uint32_t GetNumRanges(); + + lldb::SBAddress GetRangeStartAddress(uint32_t idx); + + lldb::SBAddress GetRangeEndAddress(uint32_t idx); + + uint32_t GetRangeIndexForBlockAddress(lldb::SBAddress block_addr); + + lldb::SBValueList GetVariables(lldb::SBFrame &frame, bool arguments, + bool locals, bool statics, + lldb::DynamicValueType use_dynamic); + + lldb::SBValueList GetVariables(lldb::SBTarget &target, bool arguments, + bool locals, bool statics); + //------------------------------------------------------------------ + /// Get the inlined block that contains this block. + /// + /// @return + /// If this block is inlined, it will return this block, else + /// parent blocks will be searched to see if any contain this + /// block and are themselves inlined. An invalid SBBlock will + /// be returned if this block nor any parent blocks are inlined + /// function blocks. + //------------------------------------------------------------------ + lldb::SBBlock GetContainingInlinedBlock(); + + bool GetDescription(lldb::SBStream &description); + +private: + friend class SBAddress; + friend class SBFrame; + friend class SBFunction; + friend class SBSymbolContext; + + lldb_private::Block *GetPtr(); + + void SetPtr(lldb_private::Block *lldb_object_ptr); + + SBBlock(lldb_private::Block *lldb_object_ptr); + + void AppendVariables(bool can_create, bool get_parent_variables, + lldb_private::VariableList *var_list); + + lldb_private::Block *m_opaque_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBBlock_h_ diff --git a/include/lldb/API/SBBreakpoint.h b/include/lldb/API/SBBreakpoint.h new file mode 100644 index 000000000..9abc9cd39 --- /dev/null +++ b/include/lldb/API/SBBreakpoint.h @@ -0,0 +1,176 @@ +//===-- SBBreakpoint.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBBreakpoint_h_ +#define LLDB_SBBreakpoint_h_ + +#include "lldb/API/SBDefines.h" + +class SBBreakpointListImpl; + +namespace lldb { + +class LLDB_API SBBreakpoint { +public: + typedef bool (*BreakpointHitCallback)(void *baton, SBProcess &process, + SBThread &thread, + lldb::SBBreakpointLocation &location); + + SBBreakpoint(); + + SBBreakpoint(const lldb::SBBreakpoint &rhs); + + ~SBBreakpoint(); + + const lldb::SBBreakpoint &operator=(const lldb::SBBreakpoint &rhs); + + // Tests to see if the opaque breakpoint object in this object matches the + // opaque breakpoint object in "rhs". + bool operator==(const lldb::SBBreakpoint &rhs); + + bool operator!=(const lldb::SBBreakpoint &rhs); + + break_id_t GetID() const; + + bool IsValid() const; + + void ClearAllBreakpointSites(); + + lldb::SBBreakpointLocation FindLocationByAddress(lldb::addr_t vm_addr); + + lldb::break_id_t FindLocationIDByAddress(lldb::addr_t vm_addr); + + lldb::SBBreakpointLocation FindLocationByID(lldb::break_id_t bp_loc_id); + + lldb::SBBreakpointLocation GetLocationAtIndex(uint32_t index); + + void SetEnabled(bool enable); + + bool IsEnabled(); + + void SetOneShot(bool one_shot); + + bool IsOneShot() const; + + bool IsInternal(); + + uint32_t GetHitCount() const; + + void SetIgnoreCount(uint32_t count); + + uint32_t GetIgnoreCount() const; + + void SetCondition(const char *condition); + + const char *GetCondition(); + + void SetThreadID(lldb::tid_t sb_thread_id); + + lldb::tid_t GetThreadID(); + + void SetThreadIndex(uint32_t index); + + uint32_t GetThreadIndex() const; + + void SetThreadName(const char *thread_name); + + const char *GetThreadName() const; + + void SetQueueName(const char *queue_name); + + const char *GetQueueName() const; + + void SetCallback(BreakpointHitCallback callback, void *baton); + + void SetScriptCallbackFunction(const char *callback_function_name); + + void SetCommandLineCommands(SBStringList &commands); + + bool GetCommandLineCommands(SBStringList &commands); + + SBError SetScriptCallbackBody(const char *script_body_text); + + bool AddName(const char *new_name); + + void RemoveName(const char *name_to_remove); + + bool MatchesName(const char *name); + + void GetNames(SBStringList &names); + + size_t GetNumResolvedLocations() const; + + size_t GetNumLocations() const; + + bool GetDescription(lldb::SBStream &description); + + bool GetDescription(lldb::SBStream &description, bool include_locations); + + static bool EventIsBreakpointEvent(const lldb::SBEvent &event); + + static lldb::BreakpointEventType + GetBreakpointEventTypeFromEvent(const lldb::SBEvent &event); + + static lldb::SBBreakpoint GetBreakpointFromEvent(const lldb::SBEvent &event); + + static lldb::SBBreakpointLocation + GetBreakpointLocationAtIndexFromEvent(const lldb::SBEvent &event, + uint32_t loc_idx); + + static uint32_t + GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp); + +private: + friend class SBBreakpointList; + friend class SBBreakpointLocation; + friend class SBTarget; + + SBBreakpoint(const lldb::BreakpointSP &bp_sp); + + static bool PrivateBreakpointHitCallback( + void *baton, lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + lldb::BreakpointSP GetSP() const; + + lldb::BreakpointWP m_opaque_wp; +}; + +class LLDB_API SBBreakpointList { +public: + SBBreakpointList(SBTarget &target); + + ~SBBreakpointList(); + + size_t GetSize() const; + + SBBreakpoint GetBreakpointAtIndex(size_t idx); + + SBBreakpoint FindBreakpointByID(lldb::break_id_t); + + void Append(const SBBreakpoint &sb_bkpt); + + bool AppendIfUnique(const SBBreakpoint &sb_bkpt); + + void AppendByID(lldb::break_id_t id); + + void Clear(); + +protected: + friend class SBTarget; + + void CopyToBreakpointIDList(lldb_private::BreakpointIDList &bp_id_list); + +private: + std::shared_ptr m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBBreakpoint_h_ diff --git a/include/lldb/API/SBBreakpointLocation.h b/include/lldb/API/SBBreakpointLocation.h new file mode 100644 index 000000000..0b5ba79d7 --- /dev/null +++ b/include/lldb/API/SBBreakpointLocation.h @@ -0,0 +1,88 @@ +//===-- SBBreakpointLocation.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBBreakpointLocation_h_ +#define LLDB_SBBreakpointLocation_h_ + +#include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBBreakpointLocation { +public: + SBBreakpointLocation(); + + SBBreakpointLocation(const lldb::SBBreakpointLocation &rhs); + + ~SBBreakpointLocation(); + + const lldb::SBBreakpointLocation & + operator=(const lldb::SBBreakpointLocation &rhs); + + break_id_t GetID(); + + bool IsValid() const; + + lldb::SBAddress GetAddress(); + + lldb::addr_t GetLoadAddress(); + + void SetEnabled(bool enabled); + + bool IsEnabled(); + + uint32_t GetIgnoreCount(); + + void SetIgnoreCount(uint32_t n); + + void SetCondition(const char *condition); + + const char *GetCondition(); + + void SetScriptCallbackFunction(const char *callback_function_name); + + SBError SetScriptCallbackBody(const char *script_body_text); + + void SetThreadID(lldb::tid_t sb_thread_id); + + lldb::tid_t GetThreadID(); + + void SetThreadIndex(uint32_t index); + + uint32_t GetThreadIndex() const; + + void SetThreadName(const char *thread_name); + + const char *GetThreadName() const; + + void SetQueueName(const char *queue_name); + + const char *GetQueueName() const; + + bool IsResolved(); + + bool GetDescription(lldb::SBStream &description, DescriptionLevel level); + + SBBreakpoint GetBreakpoint(); + + SBBreakpointLocation(const lldb::BreakpointLocationSP &break_loc_sp); + +private: + friend class SBBreakpoint; + + void SetLocation(const lldb::BreakpointLocationSP &break_loc_sp); + BreakpointLocationSP GetSP() const; + + lldb::BreakpointLocationWP m_opaque_wp; +}; + +} // namespace lldb + +#endif // LLDB_SBBreakpointLocation_h_ diff --git a/include/lldb/API/SBBroadcaster.h b/include/lldb/API/SBBroadcaster.h new file mode 100644 index 000000000..3fc47af65 --- /dev/null +++ b/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/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBBroadcaster { +public: + SBBroadcaster(); + + SBBroadcaster(const char *name); + + SBBroadcaster(const SBBroadcaster &rhs); + + const SBBroadcaster &operator=(const SBBroadcaster &rhs); + + ~SBBroadcaster(); + + bool IsValid() const; + + void Clear(); + + void BroadcastEventByType(uint32_t event_type, bool unique = false); + + void BroadcastEvent(const lldb::SBEvent &event, bool unique = false); + + void AddInitialEventsToListener(const lldb::SBListener &listener, + uint32_t requested_events); + + uint32_t AddListener(const lldb::SBListener &listener, uint32_t event_mask); + + const char *GetName() const; + + bool EventTypeHasListeners(uint32_t event_type); + + bool RemoveListener(const lldb::SBListener &listener, + uint32_t event_mask = UINT32_MAX); + + // This comparison is checking if the internal opaque pointer value + // is equal to that in "rhs". + bool operator==(const lldb::SBBroadcaster &rhs) const; + + // This comparison is checking if the internal opaque pointer value + // is not equal to that in "rhs". + bool operator!=(const lldb::SBBroadcaster &rhs) const; + + // This comparison is checking if the internal opaque pointer value + // is less than that in "rhs" so SBBroadcaster objects can be contained + // in ordered containers. + bool operator<(const lldb::SBBroadcaster &rhs) const; + +protected: + friend class SBCommandInterpreter; + friend class SBCommunication; + friend class SBEvent; + friend class SBListener; + friend class SBProcess; + friend class SBTarget; + + SBBroadcaster(lldb_private::Broadcaster *broadcaster, bool owns); + + lldb_private::Broadcaster *get() const; + + void reset(lldb_private::Broadcaster *broadcaster, bool owns); + +private: + lldb::BroadcasterSP m_opaque_sp; + lldb_private::Broadcaster *m_opaque_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBBroadcaster_h_ diff --git a/include/lldb/API/SBCommandInterpreter.h b/include/lldb/API/SBCommandInterpreter.h new file mode 100644 index 000000000..f68407174 --- /dev/null +++ b/include/lldb/API/SBCommandInterpreter.h @@ -0,0 +1,284 @@ +//===-- 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_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBCommandInterpreterRunOptions { + friend class SBDebugger; + friend class SBCommandInterpreter; + +public: + SBCommandInterpreterRunOptions(); + ~SBCommandInterpreterRunOptions(); + + bool GetStopOnContinue() const; + + void SetStopOnContinue(bool); + + bool GetStopOnError() const; + + void SetStopOnError(bool); + + bool GetStopOnCrash() const; + + void SetStopOnCrash(bool); + + bool GetEchoCommands() const; + + void SetEchoCommands(bool); + + bool GetPrintResults() const; + + void SetPrintResults(bool); + + bool GetAddToHistory() const; + + void SetAddToHistory(bool); + +private: + lldb_private::CommandInterpreterRunOptions *get() const; + + lldb_private::CommandInterpreterRunOptions &ref() const; + + // This is set in the constructor and will always be valid. + mutable std::unique_ptr + m_opaque_up; +}; + +class SBCommandInterpreter { +public: + enum { + eBroadcastBitThreadShouldExit = (1 << 0), + eBroadcastBitResetPrompt = (1 << 1), + eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit + eBroadcastBitAsynchronousOutputData = (1 << 3), + eBroadcastBitAsynchronousErrorData = (1 << 4) + }; + + SBCommandInterpreter(const lldb::SBCommandInterpreter &rhs); + + ~SBCommandInterpreter(); + + const lldb::SBCommandInterpreter & + operator=(const lldb::SBCommandInterpreter &rhs); + + static const char * + GetArgumentTypeAsCString(const lldb::CommandArgumentType arg_type); + + static const char * + GetArgumentDescriptionAsCString(const lldb::CommandArgumentType arg_type); + + static bool EventIsCommandInterpreterEvent(const lldb::SBEvent &event); + + bool IsValid() const; + + bool CommandExists(const char *cmd); + + bool AliasExists(const char *cmd); + + lldb::SBBroadcaster GetBroadcaster(); + + static const char *GetBroadcasterClass(); + + bool HasCommands(); + + bool HasAliases(); + + bool HasAliasOptions(); + + lldb::SBProcess GetProcess(); + + lldb::SBDebugger GetDebugger(); + + lldb::SBCommand AddMultiwordCommand(const char *name, const char *help); + + lldb::SBCommand AddCommand(const char *name, + lldb::SBCommandPluginInterface *impl, + const char *help); + + lldb::SBCommand AddCommand(const char *name, + lldb::SBCommandPluginInterface *impl, + const char *help, const char *syntax); + + 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); + + lldb::ReturnStatus HandleCommand(const char *command_line, + SBExecutionContext &exe_ctx, + SBCommandReturnObject &result, + bool add_to_history = false); + + void HandleCommandsFromFile(lldb::SBFileSpec &file, + lldb::SBExecutionContext &override_context, + lldb::SBCommandInterpreterRunOptions &options, + lldb::SBCommandReturnObject result); + + // The pointer based interface is not useful in SWIG, since the cursor & + // last_char arguments are string pointers INTO current_line + // and you can't do that in a scripting language interface in general... + + // In either case, the way this works is that the you give it a line and + // cursor position in the line. The function + // will return the number of completions. The matches list will contain + // number_of_completions + 1 elements. The first + // element is the common substring after the cursor position for all the + // matches. The rest of the elements are the + // matches. The first element is useful if you are emulating the common shell + // behavior where the tab completes + // to the string that is common among all the matches, then you should first + // check if the first element is non-empty, + // and if so just insert it and move the cursor to the end of the insertion. + // The next tab will return an empty + // common substring, and a list of choices (if any), at which point you should + // display the choices and let the user + // type further to disambiguate. + + int HandleCompletion(const char *current_line, const char *cursor, + const char *last_char, int match_start_point, + int max_return_elements, lldb::SBStringList &matches); + + int HandleCompletion(const char *current_line, uint32_t cursor_pos, + int match_start_point, int max_return_elements, + lldb::SBStringList &matches); + + // Catch commands before they execute by registering a callback that will + // get called when the command gets executed. This allows GUI or command + // line interfaces to intercept a command and stop it from happening + bool SetCommandOverrideCallback(const char *command_name, + lldb::CommandOverrideCallback callback, + void *baton); + + SBCommandInterpreter( + lldb_private::CommandInterpreter *interpreter_ptr = + nullptr); // Access using SBDebugger::GetCommandInterpreter(); + + //---------------------------------------------------------------------- + /// Return true if the command interpreter is the active IO handler. + /// + /// This indicates that any input coming into the debugger handles will + /// go to the command interpreter and will result in LLDB command line + /// commands being executed. + //---------------------------------------------------------------------- + bool IsActive(); + + //---------------------------------------------------------------------- + /// Get the string that needs to be written to the debugger stdin file + /// handle when a control character is typed. + /// + /// Some GUI programs will intercept "control + char" sequences and want + /// to have them do what normally would happen when using a real + /// terminal, so this function allows GUI programs to emulate this + /// functionality. + /// + /// @param[in] ch + /// The character that was typed along with the control key + /// + /// @return + /// The string that should be written into the file handle that is + /// feeding the input stream for the debugger, or nullptr if there is + /// no string for this control key. + //---------------------------------------------------------------------- + const char *GetIOHandlerControlSequence(char ch); + + bool GetPromptOnQuit(); + + void SetPromptOnQuit(bool b); + + //---------------------------------------------------------------------- + /// Resolve the command just as HandleCommand would, expanding abbreviations + /// and aliases. If successful, result->GetOutput has the full expansion. + //---------------------------------------------------------------------- + void ResolveCommand(const char *command_line, SBCommandReturnObject &result); + +protected: + lldb_private::CommandInterpreter &ref(); + + lldb_private::CommandInterpreter *get(); + + void reset(lldb_private::CommandInterpreter *); + +private: + friend class SBDebugger; + + static void InitializeSWIG(); + + lldb_private::CommandInterpreter *m_opaque_ptr; +}; + +class SBCommandPluginInterface { +public: + virtual ~SBCommandPluginInterface() = default; + + virtual bool DoExecute(lldb::SBDebugger /*debugger*/, char ** /*command*/, + lldb::SBCommandReturnObject & /*result*/) { + return false; + } +}; + +class SBCommand { +public: + SBCommand(); + + bool IsValid(); + + const char *GetName(); + + const char *GetHelp(); + + const char *GetHelpLong(); + + void SetHelp(const char *); + + void SetHelpLong(const char *); + + uint32_t GetFlags(); + + void SetFlags(uint32_t flags); + + lldb::SBCommand AddMultiwordCommand(const char *name, + const char *help = nullptr); + + lldb::SBCommand AddCommand(const char *name, + lldb::SBCommandPluginInterface *impl, + const char *help = nullptr); + + lldb::SBCommand AddCommand(const char *name, + lldb::SBCommandPluginInterface *impl, + const char *help, const char *syntax); + +private: + friend class SBDebugger; + friend class SBCommandInterpreter; + + SBCommand(lldb::CommandObjectSP cmd_sp); + + lldb::CommandObjectSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBCommandInterpreter_h_ diff --git a/include/lldb/API/SBCommandReturnObject.h b/include/lldb/API/SBCommandReturnObject.h new file mode 100644 index 000000000..c73e3f7cf --- /dev/null +++ b/include/lldb/API/SBCommandReturnObject.h @@ -0,0 +1,113 @@ +//===-- 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_ + +// C Includes +#include + +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBCommandReturnObject { +public: + SBCommandReturnObject(); + + SBCommandReturnObject(const lldb::SBCommandReturnObject &rhs); + + ~SBCommandReturnObject(); + + const lldb::SBCommandReturnObject & + operator=(const lldb::SBCommandReturnObject &rhs); + + SBCommandReturnObject(lldb_private::CommandReturnObject *ptr); + + lldb_private::CommandReturnObject *Release(); + + bool IsValid() const; + + const char *GetOutput(); + + const char *GetError(); + + size_t PutOutput(FILE *fh); + + size_t GetOutputSize(); + + size_t GetErrorSize(); + + size_t PutError(FILE *fh); + + void Clear(); + + lldb::ReturnStatus GetStatus(); + + void SetStatus(lldb::ReturnStatus status); + + bool Succeeded(); + + bool HasResult(); + + void AppendMessage(const char *message); + + void AppendWarning(const char *message); + + bool GetDescription(lldb::SBStream &description); + + // deprecated, these two functions do not take + // ownership of file handle + void SetImmediateOutputFile(FILE *fh); + + void SetImmediateErrorFile(FILE *fh); + + void SetImmediateOutputFile(FILE *fh, bool transfer_ownership); + + void SetImmediateErrorFile(FILE *fh, bool transfer_ownership); + + void PutCString(const char *string, int len = -1); + + size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3))); + + const char *GetOutput(bool only_if_no_immediate); + + const char *GetError(bool only_if_no_immediate); + + void SetError(lldb::SBError &error, + const char *fallback_error_cstr = nullptr); + + void SetError(const char *error_cstr); + +protected: + friend class SBCommandInterpreter; + friend class SBOptions; + + lldb_private::CommandReturnObject *operator->() const; + + lldb_private::CommandReturnObject *get() const; + + lldb_private::CommandReturnObject &operator*() const; + + lldb_private::CommandReturnObject &ref() const; + + void SetLLDBObjectPtr(lldb_private::CommandReturnObject *ptr); + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBCommandReturnObject_h_ diff --git a/include/lldb/API/SBCommunication.h b/include/lldb/API/SBCommunication.h new file mode 100644 index 000000000..f0016275b --- /dev/null +++ b/include/lldb/API/SBCommunication.h @@ -0,0 +1,82 @@ +//===-- SBCommunication.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBCommunication_h_ +#define LLDB_SBCommunication_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBError.h" + +namespace lldb { + +class LLDB_API SBCommunication { +public: + FLAGS_ANONYMOUS_ENUM(){ + eBroadcastBitDisconnected = + (1 << 0), ///< Sent when the communications connection is lost. + eBroadcastBitReadThreadGotBytes = + (1 << 1), ///< Sent by the read thread when bytes become available. + eBroadcastBitReadThreadDidExit = + (1 + << 2), ///< Sent by the read thread when it exits to inform clients. + eBroadcastBitReadThreadShouldExit = + (1 << 3), ///< Sent by clients that need to cancel the read thread. + eBroadcastBitPacketAvailable = + (1 << 4), ///< Sent when data received makes a complete packet. + eAllEventBits = 0xffffffff}; + + typedef void (*ReadThreadBytesReceived)(void *baton, const void *src, + size_t src_len); + + SBCommunication(); + SBCommunication(const char *broadcaster_name); + ~SBCommunication(); + + bool IsValid() const; + + lldb::SBBroadcaster GetBroadcaster(); + + static const char *GetBroadcasterClass(); + + lldb::ConnectionStatus AdoptFileDesriptor(int fd, bool owns_fd); + + lldb::ConnectionStatus Connect(const char *url); + + lldb::ConnectionStatus Disconnect(); + + bool IsConnected() const; + + bool GetCloseOnEOF(); + + void SetCloseOnEOF(bool b); + + size_t Read(void *dst, size_t dst_len, uint32_t timeout_usec, + lldb::ConnectionStatus &status); + + size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status); + + bool ReadThreadStart(); + + bool ReadThreadStop(); + + bool ReadThreadIsRunning(); + + bool SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived callback, + void *callback_baton); + +private: + DISALLOW_COPY_AND_ASSIGN(SBCommunication); + + lldb_private::Communication *m_opaque; + bool m_opaque_owned; +}; + +} // namespace lldb + +#endif // LLDB_SBCommunication_h_ diff --git a/include/lldb/API/SBCompileUnit.h b/include/lldb/API/SBCompileUnit.h new file mode 100644 index 000000000..4d5f9f36f --- /dev/null +++ b/include/lldb/API/SBCompileUnit.h @@ -0,0 +1,96 @@ +//===-- SBCompileUnit.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBCompileUnit_h_ +#define LLDB_SBCompileUnit_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFileSpec.h" + +namespace lldb { + +class LLDB_API SBCompileUnit { +public: + SBCompileUnit(); + + SBCompileUnit(const lldb::SBCompileUnit &rhs); + + ~SBCompileUnit(); + + const lldb::SBCompileUnit &operator=(const lldb::SBCompileUnit &rhs); + + bool IsValid() const; + + lldb::SBFileSpec GetFileSpec() const; + + uint32_t GetNumLineEntries() const; + + lldb::SBLineEntry GetLineEntryAtIndex(uint32_t idx) const; + + uint32_t FindLineEntryIndex(uint32_t start_idx, uint32_t line, + lldb::SBFileSpec *inline_file_spec) const; + + uint32_t FindLineEntryIndex(uint32_t start_idx, uint32_t line, + lldb::SBFileSpec *inline_file_spec, + bool exact) const; + + SBFileSpec GetSupportFileAtIndex(uint32_t idx) const; + + uint32_t GetNumSupportFiles() const; + + uint32_t FindSupportFileIndex(uint32_t start_idx, const SBFileSpec &sb_file, + bool full); + + //------------------------------------------------------------------ + /// Get all types matching \a type_mask from debug info in this + /// compile unit. + /// + /// @param[in] type_mask + /// A bitfield that consists of one or more bits logically OR'ed + /// together from the lldb::TypeClass enumeration. This allows + /// you to request only structure types, or only class, struct + /// and union types. Passing in lldb::eTypeClassAny will return + /// all types found in the debug information for this compile + /// unit. + /// + /// @return + /// A list of types in this compile unit that match \a type_mask + //------------------------------------------------------------------ + lldb::SBTypeList GetTypes(uint32_t type_mask = lldb::eTypeClassAny); + + lldb::LanguageType GetLanguage(); + + bool operator==(const lldb::SBCompileUnit &rhs) const; + + bool operator!=(const lldb::SBCompileUnit &rhs) const; + + bool GetDescription(lldb::SBStream &description); + +private: + friend class SBAddress; + friend class SBFrame; + friend class SBSymbolContext; + friend class SBModule; + + SBCompileUnit(lldb_private::CompileUnit *lldb_object_ptr); + + const lldb_private::CompileUnit *operator->() const; + + const lldb_private::CompileUnit &operator*() const; + + lldb_private::CompileUnit *get(); + + void reset(lldb_private::CompileUnit *lldb_object_ptr); + + lldb_private::CompileUnit *m_opaque_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBCompileUnit_h_ diff --git a/include/lldb/API/SBData.h b/include/lldb/API/SBData.h new file mode 100644 index 000000000..7aa4ea0ff --- /dev/null +++ b/include/lldb/API/SBData.h @@ -0,0 +1,156 @@ +//===-- SBData.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBData_h_ +#define LLDB_SBData_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBData { +public: + SBData(); + + SBData(const SBData &rhs); + + const SBData &operator=(const SBData &rhs); + + ~SBData(); + + uint8_t GetAddressByteSize(); + + void SetAddressByteSize(uint8_t addr_byte_size); + + void Clear(); + + bool IsValid(); + + size_t GetByteSize(); + + lldb::ByteOrder GetByteOrder(); + + void SetByteOrder(lldb::ByteOrder endian); + + float GetFloat(lldb::SBError &error, lldb::offset_t offset); + + double GetDouble(lldb::SBError &error, lldb::offset_t offset); + + long double GetLongDouble(lldb::SBError &error, lldb::offset_t offset); + + lldb::addr_t GetAddress(lldb::SBError &error, lldb::offset_t offset); + + uint8_t GetUnsignedInt8(lldb::SBError &error, lldb::offset_t offset); + + uint16_t GetUnsignedInt16(lldb::SBError &error, lldb::offset_t offset); + + uint32_t GetUnsignedInt32(lldb::SBError &error, lldb::offset_t offset); + + uint64_t GetUnsignedInt64(lldb::SBError &error, lldb::offset_t offset); + + int8_t GetSignedInt8(lldb::SBError &error, lldb::offset_t offset); + + int16_t GetSignedInt16(lldb::SBError &error, lldb::offset_t offset); + + int32_t GetSignedInt32(lldb::SBError &error, lldb::offset_t offset); + + int64_t GetSignedInt64(lldb::SBError &error, lldb::offset_t offset); + + const char *GetString(lldb::SBError &error, lldb::offset_t offset); + + size_t ReadRawData(lldb::SBError &error, lldb::offset_t offset, void *buf, + size_t size); + + bool GetDescription(lldb::SBStream &description, + lldb::addr_t base_addr = LLDB_INVALID_ADDRESS); + + // it would be nice to have SetData(SBError, const void*, size_t) when + // endianness and address size can be + // inferred from the existing DataExtractor, but having two SetData() + // signatures triggers a SWIG bug where + // the typemap isn't applied before resolving the overload, and thus the right + // function never gets called + void SetData(lldb::SBError &error, const void *buf, size_t size, + lldb::ByteOrder endian, uint8_t addr_size); + + // see SetData() for why we don't have Append(const void* buf, size_t size) + bool Append(const SBData &rhs); + + static lldb::SBData CreateDataFromCString(lldb::ByteOrder endian, + uint32_t addr_byte_size, + const char *data); + + // in the following CreateData*() and SetData*() prototypes, the two + // parameters array and array_len + // should not be renamed or rearranged, because doing so will break the SWIG + // typemap + static lldb::SBData CreateDataFromUInt64Array(lldb::ByteOrder endian, + uint32_t addr_byte_size, + uint64_t *array, + size_t array_len); + + static lldb::SBData CreateDataFromUInt32Array(lldb::ByteOrder endian, + uint32_t addr_byte_size, + uint32_t *array, + size_t array_len); + + static lldb::SBData CreateDataFromSInt64Array(lldb::ByteOrder endian, + uint32_t addr_byte_size, + int64_t *array, + size_t array_len); + + static lldb::SBData CreateDataFromSInt32Array(lldb::ByteOrder endian, + uint32_t addr_byte_size, + int32_t *array, + size_t array_len); + + static lldb::SBData CreateDataFromDoubleArray(lldb::ByteOrder endian, + uint32_t addr_byte_size, + double *array, + size_t array_len); + + bool SetDataFromCString(const char *data); + + bool SetDataFromUInt64Array(uint64_t *array, size_t array_len); + + bool SetDataFromUInt32Array(uint32_t *array, size_t array_len); + + bool SetDataFromSInt64Array(int64_t *array, size_t array_len); + + bool SetDataFromSInt32Array(int32_t *array, size_t array_len); + + bool SetDataFromDoubleArray(double *array, size_t array_len); + +protected: + // Mimic shared pointer... + lldb_private::DataExtractor *get() const; + + lldb_private::DataExtractor *operator->() const; + + lldb::DataExtractorSP &operator*(); + + const lldb::DataExtractorSP &operator*() const; + + SBData(const lldb::DataExtractorSP &data_sp); + + void SetOpaque(const lldb::DataExtractorSP &data_sp); + +private: + friend class SBInstruction; + friend class SBProcess; + friend class SBSection; + friend class SBTarget; + friend class SBValue; + + lldb::DataExtractorSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBData_h_ diff --git a/include/lldb/API/SBDebugger.h b/include/lldb/API/SBDebugger.h new file mode 100644 index 000000000..9084943b9 --- /dev/null +++ b/include/lldb/API/SBDebugger.h @@ -0,0 +1,273 @@ +//===-- 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 + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBPlatform.h" + +namespace lldb { + +class LLDB_API SBInputReader { +public: + SBInputReader() = default; + ~SBInputReader() = default; + + SBError Initialize(lldb::SBDebugger &, + unsigned long (*)(void *, lldb::SBInputReader *, + lldb::InputReaderAction, char const *, + unsigned long), + void *, lldb::InputReaderGranularity, char const *, + char const *, bool); + void SetIsDone(bool); + bool IsActive() const; +}; + +class LLDB_API SBDebugger { +public: + SBDebugger(); + + SBDebugger(const lldb::SBDebugger &rhs); + + SBDebugger(const lldb::DebuggerSP &debugger_sp); + + ~SBDebugger(); + + lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs); + + static void Initialize(); + + static void Terminate(); + + // Deprecated, use the one that takes a source_init_files bool. + static lldb::SBDebugger Create(); + + static lldb::SBDebugger Create(bool source_init_files); + + static lldb::SBDebugger Create(bool source_init_files, + lldb::LogOutputCallback log_callback, + void *baton); + + static void Destroy(lldb::SBDebugger &debugger); + + static void MemoryPressureDetected(); + + bool IsValid() const; + + void Clear(); + + void SetAsync(bool b); + + bool GetAsync(); + + void SkipLLDBInitFiles(bool b); + + void SkipAppInitFiles(bool b); + + void SetInputFileHandle(FILE *f, bool transfer_ownership); + + void SetOutputFileHandle(FILE *f, bool transfer_ownership); + + void SetErrorFileHandle(FILE *f, bool transfer_ownership); + + FILE *GetInputFileHandle(); + + FILE *GetOutputFileHandle(); + + FILE *GetErrorFileHandle(); + + void SaveInputTerminalState(); + + void RestoreInputTerminalState(); + + lldb::SBCommandInterpreter GetCommandInterpreter(); + + void HandleCommand(const char *command); + + lldb::SBListener GetListener(); + + void HandleProcessEvent(const lldb::SBProcess &process, + const lldb::SBEvent &event, FILE *out, FILE *err); + + lldb::SBTarget CreateTarget(const char *filename, const char *target_triple, + const char *platform_name, + bool add_dependent_modules, lldb::SBError &error); + + lldb::SBTarget CreateTargetWithFileAndTargetTriple(const char *filename, + const char *target_triple); + + lldb::SBTarget CreateTargetWithFileAndArch(const char *filename, + const char *archname); + + lldb::SBTarget CreateTarget(const char *filename); + + // Return true if target is deleted from the target list of the debugger. + bool DeleteTarget(lldb::SBTarget &target); + + lldb::SBTarget GetTargetAtIndex(uint32_t idx); + + uint32_t GetIndexOfTarget(lldb::SBTarget target); + + lldb::SBTarget FindTargetWithProcessID(pid_t pid); + + lldb::SBTarget FindTargetWithFileAndArch(const char *filename, + const char *arch); + + uint32_t GetNumTargets(); + + lldb::SBTarget GetSelectedTarget(); + + void SetSelectedTarget(SBTarget &target); + + lldb::SBPlatform GetSelectedPlatform(); + + void SetSelectedPlatform(lldb::SBPlatform &platform); + + lldb::SBSourceManager GetSourceManager(); + + // REMOVE: just for a quick fix, need to expose platforms through + // SBPlatform from this class. + lldb::SBError SetCurrentPlatform(const char *platform_name); + + bool SetCurrentPlatformSDKRoot(const char *sysroot); + + // FIXME: Once we get the set show stuff in place, the driver won't need + // an interface to the Set/Get UseExternalEditor. + bool SetUseExternalEditor(bool input); + + bool GetUseExternalEditor(); + + bool SetUseColor(bool use_color); + + bool GetUseColor() const; + + static bool GetDefaultArchitecture(char *arch_name, size_t arch_name_len); + + static bool SetDefaultArchitecture(const char *arch_name); + + lldb::ScriptLanguage GetScriptingLanguage(const char *script_language_name); + + static const char *GetVersionString(); + + static const char *StateAsCString(lldb::StateType state); + + static bool StateIsRunningState(lldb::StateType state); + + static bool StateIsStoppedState(lldb::StateType state); + + bool EnableLog(const char *channel, const char **categories); + + void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton); + + // DEPRECATED + void DispatchInput(void *baton, const void *data, size_t data_len); + + void DispatchInput(const void *data, size_t data_len); + + void DispatchInputInterrupt(); + + void DispatchInputEndOfFile(); + + void PushInputReader(lldb::SBInputReader &reader); + + const char *GetInstanceName(); + + static SBDebugger FindDebuggerWithID(int id); + + static lldb::SBError SetInternalVariable(const char *var_name, + const char *value, + const char *debugger_instance_name); + + static lldb::SBStringList + GetInternalVariableValue(const char *var_name, + const char *debugger_instance_name); + + bool GetDescription(lldb::SBStream &description); + + uint32_t GetTerminalWidth() const; + + void SetTerminalWidth(uint32_t term_width); + + lldb::user_id_t GetID(); + + const char *GetPrompt() const; + + void SetPrompt(const char *prompt); + + lldb::ScriptLanguage GetScriptLanguage() const; + + void SetScriptLanguage(lldb::ScriptLanguage script_lang); + + bool GetCloseInputOnEOF() const; + + void SetCloseInputOnEOF(bool b); + + SBTypeCategory GetCategory(const char *category_name); + + SBTypeCategory GetCategory(lldb::LanguageType lang_type); + + SBTypeCategory CreateCategory(const char *category_name); + + bool DeleteCategory(const char *category_name); + + uint32_t GetNumCategories(); + + SBTypeCategory GetCategoryAtIndex(uint32_t); + + SBTypeCategory GetDefaultCategory(); + + SBTypeFormat GetFormatForType(SBTypeNameSpecifier); + +#ifndef LLDB_DISABLE_PYTHON + SBTypeSummary GetSummaryForType(SBTypeNameSpecifier); +#endif + + SBTypeFilter GetFilterForType(SBTypeNameSpecifier); + +#ifndef LLDB_DISABLE_PYTHON + SBTypeSynthetic GetSyntheticForType(SBTypeNameSpecifier); +#endif + + void RunCommandInterpreter(bool auto_handle_events, bool spawn_thread); + + void RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, + SBCommandInterpreterRunOptions &options, + int &num_errors, bool &quit_requested, + bool &stopped_for_crash); + + SBError RunREPL(lldb::LanguageType language, const char *repl_options); + +private: + friend class SBCommandInterpreter; + friend class SBInputReader; + friend class SBListener; + friend class SBProcess; + friend class SBSourceManager; + friend class SBTarget; + + lldb::SBTarget FindTargetWithLLDBProcess(const lldb::ProcessSP &processSP); + + void reset(const lldb::DebuggerSP &debugger_sp); + + lldb_private::Debugger *get() const; + + lldb_private::Debugger &ref() const; + + const lldb::DebuggerSP &get_sp() const; + + lldb::DebuggerSP m_opaque_sp; + +}; // class SBDebugger + +} // namespace lldb + +#endif // LLDB_SBDebugger_h_ diff --git a/include/lldb/API/SBDeclaration.h b/include/lldb/API/SBDeclaration.h new file mode 100644 index 000000000..42cf76963 --- /dev/null +++ b/include/lldb/API/SBDeclaration.h @@ -0,0 +1,70 @@ +//===-- SBDeclaration.h -------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBDeclaration_h_ +#define LLDB_SBDeclaration_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFileSpec.h" + +namespace lldb { + +class LLDB_API SBDeclaration { +public: + SBDeclaration(); + + SBDeclaration(const lldb::SBDeclaration &rhs); + + ~SBDeclaration(); + + const lldb::SBDeclaration &operator=(const lldb::SBDeclaration &rhs); + + bool IsValid() const; + + lldb::SBFileSpec GetFileSpec() const; + + uint32_t GetLine() const; + + uint32_t GetColumn() const; + + void SetFileSpec(lldb::SBFileSpec filespec); + + void SetLine(uint32_t line); + + void SetColumn(uint32_t column); + + bool operator==(const lldb::SBDeclaration &rhs) const; + + bool operator!=(const lldb::SBDeclaration &rhs) const; + + bool GetDescription(lldb::SBStream &description); + +protected: + lldb_private::Declaration *get(); + +private: + friend class SBValue; + + const lldb_private::Declaration *operator->() const; + + lldb_private::Declaration &ref(); + + const lldb_private::Declaration &ref() const; + + SBDeclaration(const lldb_private::Declaration *lldb_object_ptr); + + void SetDeclaration(const lldb_private::Declaration &lldb_object_ref); + + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBDeclaration_h_ diff --git a/include/lldb/API/SBDefines.h b/include/lldb/API/SBDefines.h new file mode 100644 index 000000000..d70e912d9 --- /dev/null +++ b/include/lldb/API/SBDefines.h @@ -0,0 +1,103 @@ +//===-- SBDefines.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBDefines_h_ +#define LLDB_SBDefines_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" +#include "lldb/lldb-versioning.h" + +#ifdef SWIG +#define LLDB_API +#endif + +// Forward Declarations +namespace lldb { + +class LLDB_API SBAddress; +class LLDB_API SBBlock; +class LLDB_API SBBreakpoint; +class LLDB_API SBBreakpointLocation; +class LLDB_API SBBroadcaster; +class LLDB_API SBCommand; +class LLDB_API SBCommandInterpreter; +class LLDB_API SBCommandInterpreterRunOptions; +class LLDB_API SBCommandPluginInterface; +class LLDB_API SBCommandReturnObject; +class LLDB_API SBCommunication; +class LLDB_API SBCompileUnit; +class LLDB_API SBData; +class LLDB_API SBDebugger; +class LLDB_API SBDeclaration; +class LLDB_API SBError; +class LLDB_API SBEvent; +class LLDB_API SBEventList; +class LLDB_API SBExecutionContext; +class LLDB_API SBExpressionOptions; +class LLDB_API SBFileSpec; +class LLDB_API SBFileSpecList; +class LLDB_API SBFrame; +class LLDB_API SBFunction; +class LLDB_API SBHostOS; +class LLDB_API SBInstruction; +class LLDB_API SBInstructionList; +class LLDB_API SBLanguageRuntime; +class LLDB_API SBLaunchInfo; +class LLDB_API SBLineEntry; +class LLDB_API SBListener; +class LLDB_API SBMemoryRegionInfo; +class LLDB_API SBMemoryRegionInfoList; +class LLDB_API SBModule; +class LLDB_API SBModuleSpec; +class LLDB_API SBModuleSpecList; +class LLDB_API SBProcess; +class LLDB_API SBQueue; +class LLDB_API SBQueueItem; +class LLDB_API SBSection; +class LLDB_API SBSourceManager; +class LLDB_API SBStream; +class LLDB_API SBStringList; +class LLDB_API SBStructuredData; +class LLDB_API SBSymbol; +class LLDB_API SBSymbolContext; +class LLDB_API SBSymbolContextList; +class LLDB_API SBTarget; +class LLDB_API SBThread; +class LLDB_API SBThreadCollection; +class LLDB_API SBThreadPlan; +class LLDB_API SBTrace; +class LLDB_API SBTraceOptions; +class LLDB_API SBType; +class LLDB_API SBTypeCategory; +class LLDB_API SBTypeEnumMember; +class LLDB_API SBTypeEnumMemberList; +class LLDB_API SBTypeFilter; +class LLDB_API SBTypeFormat; +class LLDB_API SBTypeMemberFunction; +class LLDB_API SBTypeNameSpecifier; +class LLDB_API SBTypeSummary; +class LLDB_API SBTypeSummaryOptions; +class LLDB_API SBTypeSynthetic; +class LLDB_API SBTypeList; +class LLDB_API SBValue; +class LLDB_API SBValueList; +class LLDB_API SBVariablesOptions; +class LLDB_API SBWatchpoint; +class LLDB_API SBUnixSignals; +} + +#endif // LLDB_SBDefines_h_ diff --git a/include/lldb/API/SBError.h b/include/lldb/API/SBError.h new file mode 100644 index 000000000..a099a9be2 --- /dev/null +++ b/include/lldb/API/SBError.h @@ -0,0 +1,89 @@ +//===-- SBError.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBError_h_ +#define LLDB_SBError_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBError { +public: + SBError(); + + SBError(const lldb::SBError &rhs); + + ~SBError(); + + const SBError &operator=(const lldb::SBError &rhs); + + const char *GetCString() const; + + void Clear(); + + bool Fail() const; + + bool Success() const; + + uint32_t GetError() const; + + lldb::ErrorType GetType() const; + + void SetError(uint32_t err, lldb::ErrorType type); + + void SetErrorToErrno(); + + void SetErrorToGenericError(); + + void SetErrorString(const char *err_str); + + int SetErrorStringWithFormat(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + bool IsValid() const; + + bool GetDescription(lldb::SBStream &description); + +protected: + friend class SBCommandReturnObject; + friend class SBData; + friend class SBDebugger; + friend class SBCommunication; + friend class SBHostOS; + friend class SBPlatform; + friend class SBProcess; + friend class SBStructuredData; + friend class SBThread; + friend class SBTrace; + friend class SBTarget; + friend class SBValue; + friend class SBWatchpoint; + friend class SBBreakpoint; + friend class SBBreakpointLocation; + + lldb_private::Status *get(); + + lldb_private::Status *operator->(); + + const lldb_private::Status &operator*() const; + + lldb_private::Status &ref(); + + void SetError(const lldb_private::Status &lldb_error); + +private: + std::unique_ptr m_opaque_ap; + + void CreateIfNeeded(); +}; + +} // namespace lldb + +#endif // LLDB_SBError_h_ diff --git a/include/lldb/API/SBEvent.h b/include/lldb/API/SBEvent.h new file mode 100644 index 000000000..ff15716d8 --- /dev/null +++ b/include/lldb/API/SBEvent.h @@ -0,0 +1,86 @@ +//===-- SBEvent.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBEvent_h_ +#define LLDB_SBEvent_h_ + +#include "lldb/API/SBDefines.h" + +#include +#include + +namespace lldb { + +class SBBroadcaster; + +class LLDB_API SBEvent { +public: + SBEvent(); + + SBEvent(const lldb::SBEvent &rhs); + + // Make an event that contains a C string. + SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len); + + SBEvent(lldb::EventSP &event_sp); + + SBEvent(lldb_private::Event *event_sp); + + ~SBEvent(); + + const SBEvent &operator=(const lldb::SBEvent &rhs); + + bool IsValid() const; + + const char *GetDataFlavor(); + + uint32_t GetType() const; + + lldb::SBBroadcaster GetBroadcaster() const; + + const char *GetBroadcasterClass() const; + + bool BroadcasterMatchesPtr(const lldb::SBBroadcaster *broadcaster); + + bool BroadcasterMatchesRef(const lldb::SBBroadcaster &broadcaster); + + void Clear(); + + static const char *GetCStringFromEvent(const lldb::SBEvent &event); + + bool GetDescription(lldb::SBStream &description); + + bool GetDescription(lldb::SBStream &description) const; + +protected: + friend class SBListener; + friend class SBBroadcaster; + friend class SBBreakpoint; + friend class SBDebugger; + friend class SBProcess; + friend class SBTarget; + friend class SBThread; + friend class SBWatchpoint; + + lldb::EventSP &GetSP() const; + + void reset(lldb::EventSP &event_sp); + + void reset(lldb_private::Event *event); + + lldb_private::Event *get() const; + +private: + mutable lldb::EventSP m_event_sp; + mutable lldb_private::Event *m_opaque_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBEvent_h_ diff --git a/include/lldb/API/SBExecutionContext.h b/include/lldb/API/SBExecutionContext.h new file mode 100644 index 000000000..c19d539bc --- /dev/null +++ b/include/lldb/API/SBExecutionContext.h @@ -0,0 +1,66 @@ +//===-- SBExecutionContext.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_SBExecutionContext_h_ +#define LLDB_SBExecutionContext_h_ + +#include "lldb/API/SBDefines.h" + +#include +#include + +namespace lldb { + +class LLDB_API SBExecutionContext { + friend class SBCommandInterpreter; + +public: + SBExecutionContext(); + + SBExecutionContext(const lldb::SBExecutionContext &rhs); + + SBExecutionContext(lldb::ExecutionContextRefSP exe_ctx_ref_sp); + + SBExecutionContext(const lldb::SBTarget &target); + + SBExecutionContext(const lldb::SBProcess &process); + + SBExecutionContext(lldb::SBThread thread); // can't be a const& because + // SBThread::get() isn't itself a + // const function + + SBExecutionContext(const lldb::SBFrame &frame); + + ~SBExecutionContext(); + + const SBExecutionContext &operator=(const lldb::SBExecutionContext &rhs); + + SBTarget GetTarget() const; + + SBProcess GetProcess() const; + + SBThread GetThread() const; + + SBFrame GetFrame() const; + +protected: + ExecutionContextRefSP &GetSP() const; + + void reset(lldb::ExecutionContextRefSP &event_sp); + + lldb_private::ExecutionContextRef *get() const; + +private: + mutable lldb::ExecutionContextRefSP m_exe_ctx_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBExecutionContext_h_ diff --git a/include/lldb/API/SBExpressionOptions.h b/include/lldb/API/SBExpressionOptions.h new file mode 100644 index 000000000..370811d0c --- /dev/null +++ b/include/lldb/API/SBExpressionOptions.h @@ -0,0 +1,115 @@ +//===-- SBEvent.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBExpressionOptions_h_ +#define LLDB_SBExpressionOptions_h_ + +#include "lldb/API/SBDefines.h" + +#include + +namespace lldb { + +class LLDB_API SBExpressionOptions { +public: + SBExpressionOptions(); + + SBExpressionOptions(const lldb::SBExpressionOptions &rhs); + + ~SBExpressionOptions(); + + const SBExpressionOptions &operator=(const lldb::SBExpressionOptions &rhs); + + bool GetCoerceResultToId() const; + + void SetCoerceResultToId(bool coerce = true); + + bool GetUnwindOnError() const; + + void SetUnwindOnError(bool unwind = true); + + bool GetIgnoreBreakpoints() const; + + void SetIgnoreBreakpoints(bool ignore = true); + + lldb::DynamicValueType GetFetchDynamicValue() const; + + void SetFetchDynamicValue( + lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget); + + uint32_t GetTimeoutInMicroSeconds() const; + + // Set the timeout for the expression, 0 means wait forever. + void SetTimeoutInMicroSeconds(uint32_t timeout = 0); + + uint32_t GetOneThreadTimeoutInMicroSeconds() const; + + // Set the timeout for running on one thread, 0 means use the default + // behavior. + // If you set this higher than the overall timeout, you'll get an error when + // you + // try to run the expression. + void SetOneThreadTimeoutInMicroSeconds(uint32_t timeout = 0); + + bool GetTryAllThreads() const; + + void SetTryAllThreads(bool run_others = true); + + bool GetStopOthers() const; + + void SetStopOthers(bool stop_others = true); + + bool GetTrapExceptions() const; + + void SetTrapExceptions(bool trap_exceptions = true); + + void SetLanguage(lldb::LanguageType language); + + void SetCancelCallback(lldb::ExpressionCancelCallback callback, void *baton); + + bool GetGenerateDebugInfo(); + + void SetGenerateDebugInfo(bool b = true); + + bool GetSuppressPersistentResult(); + + void SetSuppressPersistentResult(bool b = false); + + const char *GetPrefix() const; + + void SetPrefix(const char *prefix); + + void SetAutoApplyFixIts(bool b = true); + + bool GetAutoApplyFixIts(); + + bool GetTopLevel(); + + void SetTopLevel(bool b = true); + +protected: + SBExpressionOptions( + lldb_private::EvaluateExpressionOptions &expression_options); + + lldb_private::EvaluateExpressionOptions *get() const; + + lldb_private::EvaluateExpressionOptions &ref() const; + + friend class SBFrame; + friend class SBValue; + friend class SBTarget; + +private: + // This auto_pointer is made in the constructor and is always valid. + mutable std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBExpressionOptions_h_ diff --git a/include/lldb/API/SBFileSpec.h b/include/lldb/API/SBFileSpec.h new file mode 100644 index 000000000..a31d95abb --- /dev/null +++ b/include/lldb/API/SBFileSpec.h @@ -0,0 +1,89 @@ +//===-- SBFileSpec.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBFileSpec_h_ +#define LLDB_SBFileSpec_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBFileSpec { +public: + SBFileSpec(); + + SBFileSpec(const lldb::SBFileSpec &rhs); + + SBFileSpec(const char *path); // Deprecated, use SBFileSpec (const char *path, + // bool resolve) + + SBFileSpec(const char *path, bool resolve); + + ~SBFileSpec(); + + const SBFileSpec &operator=(const lldb::SBFileSpec &rhs); + + bool IsValid() const; + + bool Exists() const; + + bool ResolveExecutableLocation(); + + const char *GetFilename() const; + + const char *GetDirectory() const; + + void SetFilename(const char *filename); + + void SetDirectory(const char *directory); + + uint32_t GetPath(char *dst_path, size_t dst_len) const; + + static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len); + + bool GetDescription(lldb::SBStream &description) const; + + void AppendPathComponent(const char *file_or_directory); + +private: + friend class SBAttachInfo; + friend class SBBlock; + friend class SBCommandInterpreter; + friend class SBCompileUnit; + friend class SBDeclaration; + friend class SBFileSpecList; + friend class SBHostOS; + friend class SBLaunchInfo; + friend class SBLineEntry; + friend class SBModule; + friend class SBModuleSpec; + friend class SBPlatform; + friend class SBProcess; + friend class SBSourceManager; + friend class SBThread; + friend class SBTarget; + + SBFileSpec(const lldb_private::FileSpec &fspec); + + void SetFileSpec(const lldb_private::FileSpec &fspec); + + const lldb_private::FileSpec *operator->() const; + + const lldb_private::FileSpec *get() const; + + const lldb_private::FileSpec &operator*() const; + + const lldb_private::FileSpec &ref() const; + + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBFileSpec_h_ diff --git a/include/lldb/API/SBFileSpecList.h b/include/lldb/API/SBFileSpecList.h new file mode 100644 index 000000000..97f843adb --- /dev/null +++ b/include/lldb/API/SBFileSpecList.h @@ -0,0 +1,58 @@ +//===-- SBFileSpecList.h --------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBFileSpecList_h_ +#define LLDB_SBFileSpecList_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBFileSpecList { +public: + SBFileSpecList(); + + SBFileSpecList(const lldb::SBFileSpecList &rhs); + + ~SBFileSpecList(); + + const SBFileSpecList &operator=(const lldb::SBFileSpecList &rhs); + + uint32_t GetSize() const; + + bool GetDescription(SBStream &description) const; + + void Append(const SBFileSpec &sb_file); + + bool AppendIfUnique(const SBFileSpec &sb_file); + + void Clear(); + + uint32_t FindFileIndex(uint32_t idx, const SBFileSpec &sb_file, bool full); + + const SBFileSpec GetFileSpecAtIndex(uint32_t idx) const; + +private: + friend class SBTarget; + + const lldb_private::FileSpecList *operator->() const; + + const lldb_private::FileSpecList *get() const; + + const lldb_private::FileSpecList &operator*() const; + + const lldb_private::FileSpecList &ref() const; + + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBFileSpecList_h_ diff --git a/include/lldb/API/SBFrame.h b/include/lldb/API/SBFrame.h new file mode 100644 index 000000000..58339750d --- /dev/null +++ b/include/lldb/API/SBFrame.h @@ -0,0 +1,200 @@ +//===-- SBFrame.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBFrame_h_ +#define LLDB_SBFrame_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBValueList.h" + +namespace lldb { + +class LLDB_API SBFrame { +public: + SBFrame(); + + SBFrame(const lldb::SBFrame &rhs); + + const lldb::SBFrame &operator=(const lldb::SBFrame &rhs); + + ~SBFrame(); + + bool IsEqual(const lldb::SBFrame &that) const; + + bool IsValid() const; + + uint32_t GetFrameID() const; + + lldb::addr_t GetCFA() const; + + lldb::addr_t GetPC() const; + + bool SetPC(lldb::addr_t new_pc); + + lldb::addr_t GetSP() const; + + lldb::addr_t GetFP() const; + + lldb::SBAddress GetPCAddress() const; + + lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope) const; + + lldb::SBModule GetModule() const; + + lldb::SBCompileUnit GetCompileUnit() const; + + lldb::SBFunction GetFunction() const; + + lldb::SBSymbol GetSymbol() const; + + /// Gets the deepest block that contains the frame PC. + /// + /// See also GetFrameBlock(). + lldb::SBBlock GetBlock() const; + + /// Get the appropriate function name for this frame. Inlined functions in + /// LLDB are represented by Blocks that have inlined function information, so + /// just looking at the SBFunction or SBSymbol for a frame isn't enough. + /// This function will return the appropriate function, symbol or inlined + /// function name for the frame. + /// + /// This function returns: + /// - the name of the inlined function (if there is one) + /// - the name of the concrete function (if there is one) + /// - the name of the symbol (if there is one) + /// - NULL + /// + /// See also IsInlined(). + const char *GetFunctionName(); + + // Get an appropriate function name for this frame that is suitable for + // display to a user + const char *GetDisplayFunctionName(); + + const char *GetFunctionName() const; + + // Return the frame function's language. If there isn't a function, then + // guess the language type from the mangled name. + lldb::LanguageType GuessLanguage() const; + + /// Return true if this frame represents an inlined function. + /// + /// See also GetFunctionName(). + bool IsInlined(); + + bool IsInlined() const; + + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + lldb::SBValue EvaluateExpression(const char *expr); + + lldb::SBValue EvaluateExpression(const char *expr, + lldb::DynamicValueType use_dynamic); + + lldb::SBValue EvaluateExpression(const char *expr, + lldb::DynamicValueType use_dynamic, + bool unwind_on_error); + + lldb::SBValue EvaluateExpression(const char *expr, + const SBExpressionOptions &options); + + /// Gets the lexical block that defines the stack frame. Another way to think + /// of this is it will return the block that contains all of the variables + /// for a stack frame. Inlined functions are represented as SBBlock objects + /// that have inlined function information: the name of the inlined function, + /// where it was called from. The block that is returned will be the first + /// block at or above the block for the PC (SBFrame::GetBlock()) that defines + /// the scope of the frame. When a function contains no inlined functions, + /// this will be the top most lexical block that defines the function. + /// When a function has inlined functions and the PC is currently + /// in one of those inlined functions, this method will return the inlined + /// block that defines this frame. If the PC isn't currently in an inlined + /// function, the lexical block that defines the function is returned. + lldb::SBBlock GetFrameBlock() const; + + lldb::SBLineEntry GetLineEntry() const; + + lldb::SBThread GetThread() const; + + const char *Disassemble() const; + + void Clear(); + + bool operator==(const lldb::SBFrame &rhs) const; + + bool operator!=(const lldb::SBFrame &rhs) const; + + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + lldb::SBValueList GetVariables(bool arguments, bool locals, bool statics, + bool in_scope_only); + + lldb::SBValueList GetVariables(bool arguments, bool locals, bool statics, + bool in_scope_only, + lldb::DynamicValueType use_dynamic); + + lldb::SBValueList GetVariables(const lldb::SBVariablesOptions &options); + + lldb::SBValueList GetRegisters(); + + lldb::SBValue FindRegister(const char *name); + + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + lldb::SBValue FindVariable(const char *var_name); + + lldb::SBValue FindVariable(const char *var_name, + lldb::DynamicValueType use_dynamic); + + // Find a value for a variable expression path like "rect.origin.x" or + // "pt_ptr->x", "*self", "*this->obj_ptr". The returned value is _not_ + // and expression result and is not a constant object like + // SBFrame::EvaluateExpression(...) returns, but a child object of + // the variable value. + lldb::SBValue GetValueForVariablePath(const char *var_expr_cstr, + DynamicValueType use_dynamic); + + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + lldb::SBValue GetValueForVariablePath(const char *var_path); + + /// Find variables, register sets, registers, or persistent variables using + /// the frame as the scope. + /// + /// NB. This function does not look up ivars in the function object pointer. + /// To do that use GetValueForVariablePath. + /// + /// The version that doesn't supply a 'use_dynamic' value will use the + /// target's default. + lldb::SBValue FindValue(const char *name, ValueType value_type); + + lldb::SBValue FindValue(const char *name, ValueType value_type, + lldb::DynamicValueType use_dynamic); + + bool GetDescription(lldb::SBStream &description); + + SBFrame(const lldb::StackFrameSP &lldb_object_sp); + +protected: + friend class SBBlock; + friend class SBExecutionContext; + friend class SBInstruction; + friend class SBThread; + friend class SBValue; + + lldb::StackFrameSP GetFrameSP() const; + + void SetFrameSP(const lldb::StackFrameSP &lldb_object_sp); + + lldb::ExecutionContextRefSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBFrame_h_ diff --git a/include/lldb/API/SBFunction.h b/include/lldb/API/SBFunction.h new file mode 100644 index 000000000..23da02102 --- /dev/null +++ b/include/lldb/API/SBFunction.h @@ -0,0 +1,81 @@ +//===-- SBFunction.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBFunction_h_ +#define LLDB_SBFunction_h_ + +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBInstructionList.h" + +namespace lldb { + +class LLDB_API SBFunction { +public: + SBFunction(); + + SBFunction(const lldb::SBFunction &rhs); + + const lldb::SBFunction &operator=(const lldb::SBFunction &rhs); + + ~SBFunction(); + + bool IsValid() const; + + const char *GetName() const; + + const char *GetDisplayName() const; + + const char *GetMangledName() const; + + lldb::SBInstructionList GetInstructions(lldb::SBTarget target); + + lldb::SBInstructionList GetInstructions(lldb::SBTarget target, + const char *flavor); + + lldb::SBAddress GetStartAddress(); + + lldb::SBAddress GetEndAddress(); + + const char *GetArgumentName(uint32_t arg_idx); + + uint32_t GetPrologueByteSize(); + + lldb::SBType GetType(); + + lldb::SBBlock GetBlock(); + + lldb::LanguageType GetLanguage(); + + bool GetIsOptimized(); + + bool operator==(const lldb::SBFunction &rhs) const; + + bool operator!=(const lldb::SBFunction &rhs) const; + + bool GetDescription(lldb::SBStream &description); + +protected: + lldb_private::Function *get(); + + void reset(lldb_private::Function *lldb_object_ptr); + +private: + friend class SBAddress; + friend class SBFrame; + friend class SBSymbolContext; + + SBFunction(lldb_private::Function *lldb_object_ptr); + + lldb_private::Function *m_opaque_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBFunction_h_ diff --git a/include/lldb/API/SBHostOS.h b/include/lldb/API/SBHostOS.h new file mode 100644 index 000000000..1671917f8 --- /dev/null +++ b/include/lldb/API/SBHostOS.h @@ -0,0 +1,45 @@ +//===-- SBHostOS.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBHostOS_h_ +#define LLDB_SBHostOS_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFileSpec.h" + +namespace lldb { + +class LLDB_API SBHostOS { +public: + static lldb::SBFileSpec GetProgramFileSpec(); + + static lldb::SBFileSpec GetLLDBPythonPath(); + + static lldb::SBFileSpec GetLLDBPath(lldb::PathType path_type); + + static lldb::SBFileSpec GetUserHomeDirectory(); + + static void ThreadCreated(const char *name); + + static lldb::thread_t ThreadCreate(const char *name, + lldb::thread_func_t thread_function, + 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, lldb::thread_result_t *result, + lldb::SBError *err); + +private: +}; + +} // namespace lldb + +#endif // LLDB_SBHostOS_h_ diff --git a/include/lldb/API/SBInstruction.h b/include/lldb/API/SBInstruction.h new file mode 100644 index 000000000..23daf1c56 --- /dev/null +++ b/include/lldb/API/SBInstruction.h @@ -0,0 +1,87 @@ +//===-- SBInstruction.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBInstruction_h_ +#define LLDB_SBInstruction_h_ + +#include "lldb/API/SBData.h" +#include "lldb/API/SBDefines.h" + +#include + +// There's a lot to be fixed here, but need to wait for underlying insn +// implementation +// to be revised & settle down first. + +class InstructionImpl; + +namespace lldb { + +class LLDB_API SBInstruction { +public: + SBInstruction(); + + SBInstruction(const SBInstruction &rhs); + + const SBInstruction &operator=(const SBInstruction &rhs); + + ~SBInstruction(); + + bool IsValid(); + + SBAddress GetAddress(); + + lldb::AddressClass GetAddressClass(); + + const char *GetMnemonic(lldb::SBTarget target); + + const char *GetOperands(lldb::SBTarget target); + + const char *GetComment(lldb::SBTarget target); + + lldb::SBData GetData(lldb::SBTarget target); + + size_t GetByteSize(); + + bool DoesBranch(); + + bool HasDelaySlot(); + + bool CanSetBreakpoint(); + + void Print(FILE *out); + + bool GetDescription(lldb::SBStream &description); + + bool EmulateWithFrame(lldb::SBFrame &frame, uint32_t evaluate_options); + + bool DumpEmulation(const char *triple); // triple is to specify the + // architecture, e.g. 'armv6' or + // 'armv7-apple-ios' + + bool TestEmulation(lldb::SBStream &output_stream, const char *test_file); + +protected: + friend class SBInstructionList; + + SBInstruction(const lldb::DisassemblerSP &disasm_sp, + const lldb::InstructionSP &inst_sp); + + void SetOpaque(const lldb::DisassemblerSP &disasm_sp, + const lldb::InstructionSP &inst_sp); + + lldb::InstructionSP GetOpaque(); + +private: + std::shared_ptr m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBInstruction_h_ diff --git a/include/lldb/API/SBInstructionList.h b/include/lldb/API/SBInstructionList.h new file mode 100644 index 000000000..0323a3c80 --- /dev/null +++ b/include/lldb/API/SBInstructionList.h @@ -0,0 +1,67 @@ +//===-- SBInstructionList.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBInstructionList_h_ +#define LLDB_SBInstructionList_h_ + +#include "lldb/API/SBDefines.h" + +#include + +namespace lldb { + +class LLDB_API SBInstructionList { +public: + SBInstructionList(); + + SBInstructionList(const SBInstructionList &rhs); + + const SBInstructionList &operator=(const SBInstructionList &rhs); + + ~SBInstructionList(); + + bool IsValid() const; + + size_t GetSize(); + + lldb::SBInstruction GetInstructionAtIndex(uint32_t idx); + + // ---------------------------------------------------------------------- + // Returns the number of instructions between the start and end address. + // If canSetBreakpoint is true then the count will be the number of + // instructions on which a breakpoint can be set. + // ---------------------------------------------------------------------- + size_t GetInstructionsCount(const SBAddress &start, + const SBAddress &end, + bool canSetBreakpoint = false); + + void Clear(); + + void AppendInstruction(lldb::SBInstruction inst); + + void Print(FILE *out); + + bool GetDescription(lldb::SBStream &description); + + bool DumpEmulationForAllInstructions(const char *triple); + +protected: + friend class SBFunction; + friend class SBSymbol; + friend class SBTarget; + + void SetDisassembler(const lldb::DisassemblerSP &opaque_sp); + +private: + lldb::DisassemblerSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBInstructionList_h_ diff --git a/include/lldb/API/SBLanguageRuntime.h b/include/lldb/API/SBLanguageRuntime.h new file mode 100644 index 000000000..3912f3524 --- /dev/null +++ b/include/lldb/API/SBLanguageRuntime.h @@ -0,0 +1,26 @@ +//===-- SBLanguageRuntime.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBLanguageRuntime_h_ +#define LLDB_SBLanguageRuntime_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class SBLanguageRuntime { +public: + static lldb::LanguageType GetLanguageTypeFromString(const char *string); + + static const char *GetNameForLanguageType(lldb::LanguageType language); +}; + +} // namespace lldb + +#endif // LLDB_SBLanguageRuntime_h_ diff --git a/include/lldb/API/SBLaunchInfo.h b/include/lldb/API/SBLaunchInfo.h new file mode 100644 index 000000000..1cece2351 --- /dev/null +++ b/include/lldb/API/SBLaunchInfo.h @@ -0,0 +1,153 @@ +//===-- SBLaunchInfo.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_SBLaunchInfo_h_ +#define LLDB_SBLaunchInfo_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class SBPlatform; +class SBTarget; + +class LLDB_API SBLaunchInfo { +public: + SBLaunchInfo(const char **argv); + + ~SBLaunchInfo(); + + lldb::pid_t GetProcessID(); + + uint32_t GetUserID(); + + uint32_t GetGroupID(); + + bool UserIDIsValid(); + + bool GroupIDIsValid(); + + void SetUserID(uint32_t uid); + + void SetGroupID(uint32_t gid); + + SBFileSpec GetExecutableFile(); + + //---------------------------------------------------------------------- + /// Set the executable file that will be used to launch the process and + /// optionally set it as the first argument in the argument vector. + /// + /// This only needs to be specified if clients wish to carefully control + /// the exact path will be used to launch a binary. If you create a + /// target with a symlink, that symlink will get resolved in the target + /// and the resolved path will get used to launch the process. Calling + /// this function can help you still launch your process using the + /// path of your choice. + /// + /// If this function is not called prior to launching with + /// SBTarget::Launch(...), the target will use the resolved executable + /// path that was used to create the target. + /// + /// @param[in] exe_file + /// The override path to use when launching the executable. + /// + /// @param[in] add_as_first_arg + /// If true, then the path will be inserted into the argument vector + /// prior to launching. Otherwise the argument vector will be left + /// alone. + //---------------------------------------------------------------------- + void SetExecutableFile(SBFileSpec exe_file, bool add_as_first_arg); + + //---------------------------------------------------------------------- + /// Get the listener that will be used to receive process events. + /// + /// If no listener has been set via a call to + /// SBLaunchInfo::SetListener(), then an invalid SBListener will be + /// returned (SBListener::IsValid() will return false). If a listener + /// has been set, then the valid listener object will be returned. + //---------------------------------------------------------------------- + SBListener GetListener(); + + //---------------------------------------------------------------------- + /// Set the listener that will be used to receive process events. + /// + /// By default the SBDebugger, which has a listener, that the SBTarget + /// belongs to will listen for the process events. Calling this function + /// allows a different listener to be used to listen for process events. + //---------------------------------------------------------------------- + void SetListener(SBListener &listener); + + uint32_t GetNumArguments(); + + const char *GetArgumentAtIndex(uint32_t idx); + + void SetArguments(const char **argv, bool append); + + uint32_t GetNumEnvironmentEntries(); + + const char *GetEnvironmentEntryAtIndex(uint32_t idx); + + void SetEnvironmentEntries(const char **envp, bool append); + + void Clear(); + + const char *GetWorkingDirectory() const; + + void SetWorkingDirectory(const char *working_dir); + + uint32_t GetLaunchFlags(); + + void SetLaunchFlags(uint32_t flags); + + const char *GetProcessPluginName(); + + void SetProcessPluginName(const char *plugin_name); + + const char *GetShell(); + + void SetShell(const char *path); + + bool GetShellExpandArguments(); + + void SetShellExpandArguments(bool expand); + + uint32_t GetResumeCount(); + + void SetResumeCount(uint32_t c); + + bool AddCloseFileAction(int fd); + + bool AddDuplicateFileAction(int fd, int dup_fd); + + bool AddOpenFileAction(int fd, const char *path, bool read, bool write); + + bool AddSuppressFileAction(int fd, bool read, bool write); + + void SetLaunchEventData(const char *data); + + const char *GetLaunchEventData() const; + + bool GetDetachOnError() const; + + void SetDetachOnError(bool enable); + +protected: + friend class SBPlatform; + friend class SBTarget; + + lldb_private::ProcessLaunchInfo &ref(); + + const lldb_private::ProcessLaunchInfo &ref() const; + + ProcessLaunchInfoSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBLaunchInfo_h_ diff --git a/include/lldb/API/SBLineEntry.h b/include/lldb/API/SBLineEntry.h new file mode 100644 index 000000000..3d58ea827 --- /dev/null +++ b/include/lldb/API/SBLineEntry.h @@ -0,0 +1,77 @@ +//===-- SBLineEntry.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBLineEntry_h_ +#define LLDB_SBLineEntry_h_ + +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFileSpec.h" + +namespace lldb { + +class LLDB_API SBLineEntry { +public: + SBLineEntry(); + + SBLineEntry(const lldb::SBLineEntry &rhs); + + ~SBLineEntry(); + + const lldb::SBLineEntry &operator=(const lldb::SBLineEntry &rhs); + + lldb::SBAddress GetStartAddress() const; + + lldb::SBAddress GetEndAddress() const; + + bool IsValid() const; + + lldb::SBFileSpec GetFileSpec() const; + + uint32_t GetLine() const; + + uint32_t GetColumn() const; + + void SetFileSpec(lldb::SBFileSpec filespec); + + void SetLine(uint32_t line); + + void SetColumn(uint32_t column); + + bool operator==(const lldb::SBLineEntry &rhs) const; + + bool operator!=(const lldb::SBLineEntry &rhs) const; + + bool GetDescription(lldb::SBStream &description); + +protected: + lldb_private::LineEntry *get(); + +private: + friend class SBAddress; + friend class SBCompileUnit; + friend class SBFrame; + friend class SBSymbolContext; + + const lldb_private::LineEntry *operator->() const; + + lldb_private::LineEntry &ref(); + + const lldb_private::LineEntry &ref() const; + + SBLineEntry(const lldb_private::LineEntry *lldb_object_ptr); + + void SetLineEntry(const lldb_private::LineEntry &lldb_object_ref); + + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBLineEntry_h_ diff --git a/include/lldb/API/SBListener.h b/include/lldb/API/SBListener.h new file mode 100644 index 000000000..a2f82a83c --- /dev/null +++ b/include/lldb/API/SBListener.h @@ -0,0 +1,107 @@ +//===-- SBListener.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBListener_h_ +#define LLDB_SBListener_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBListener { +public: + SBListener(); + + SBListener(const char *name); + + SBListener(const SBListener &rhs); + + ~SBListener(); + + const lldb::SBListener &operator=(const lldb::SBListener &rhs); + + void AddEvent(const lldb::SBEvent &event); + + void Clear(); + + bool IsValid() const; + + uint32_t StartListeningForEventClass(SBDebugger &debugger, + const char *broadcaster_class, + uint32_t event_mask); + + bool StopListeningForEventClass(SBDebugger &debugger, + const char *broadcaster_class, + uint32_t event_mask); + + uint32_t StartListeningForEvents(const lldb::SBBroadcaster &broadcaster, + uint32_t event_mask); + + bool StopListeningForEvents(const lldb::SBBroadcaster &broadcaster, + uint32_t event_mask); + + // Returns true if an event was received, false if we timed out. + bool WaitForEvent(uint32_t num_seconds, lldb::SBEvent &event); + + bool WaitForEventForBroadcaster(uint32_t num_seconds, + const lldb::SBBroadcaster &broadcaster, + lldb::SBEvent &sb_event); + + bool WaitForEventForBroadcasterWithType( + uint32_t num_seconds, const lldb::SBBroadcaster &broadcaster, + uint32_t event_type_mask, lldb::SBEvent &sb_event); + + bool PeekAtNextEvent(lldb::SBEvent &sb_event); + + bool PeekAtNextEventForBroadcaster(const lldb::SBBroadcaster &broadcaster, + lldb::SBEvent &sb_event); + + bool + PeekAtNextEventForBroadcasterWithType(const lldb::SBBroadcaster &broadcaster, + uint32_t event_type_mask, + lldb::SBEvent &sb_event); + + bool GetNextEvent(lldb::SBEvent &sb_event); + + bool GetNextEventForBroadcaster(const lldb::SBBroadcaster &broadcaster, + lldb::SBEvent &sb_event); + + bool + GetNextEventForBroadcasterWithType(const lldb::SBBroadcaster &broadcaster, + uint32_t event_type_mask, + lldb::SBEvent &sb_event); + + bool HandleBroadcastEvent(const lldb::SBEvent &event); + +protected: + friend class SBAttachInfo; + friend class SBBroadcaster; + friend class SBCommandInterpreter; + friend class SBDebugger; + friend class SBLaunchInfo; + friend class SBTarget; + + SBListener(const lldb::ListenerSP &listener_sp); + + lldb::ListenerSP GetSP(); + +private: + lldb_private::Listener *operator->() const; + + lldb_private::Listener *get() const; + + void reset(lldb::ListenerSP listener_sp); + + lldb::ListenerSP m_opaque_sp; + lldb_private::Listener *m_unused_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBListener_h_ diff --git a/include/lldb/API/SBMemoryRegionInfo.h b/include/lldb/API/SBMemoryRegionInfo.h new file mode 100644 index 000000000..297f877a6 --- /dev/null +++ b/include/lldb/API/SBMemoryRegionInfo.h @@ -0,0 +1,112 @@ +//===-- SBMemoryRegionInfo.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_SBMemoryRegionInfo_h_ +#define LLDB_SBMemoryRegionInfo_h_ + +#include "lldb/API/SBData.h" +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBMemoryRegionInfo { +public: + SBMemoryRegionInfo(); + + SBMemoryRegionInfo(const lldb::SBMemoryRegionInfo &rhs); + + ~SBMemoryRegionInfo(); + + const lldb::SBMemoryRegionInfo & + operator=(const lldb::SBMemoryRegionInfo &rhs); + + void Clear(); + + //------------------------------------------------------------------ + /// Get the base address of this memory range. + /// + /// @return + /// The base address of this memory range. + //------------------------------------------------------------------ + lldb::addr_t GetRegionBase(); + + //------------------------------------------------------------------ + /// Get the end address of this memory range. + /// + /// @return + /// The base address of this memory range. + //------------------------------------------------------------------ + lldb::addr_t GetRegionEnd(); + + //------------------------------------------------------------------ + /// Check if this memory address is marked readable to the process. + /// + /// @return + /// true if this memory address is marked readable + //------------------------------------------------------------------ + bool IsReadable(); + + //------------------------------------------------------------------ + /// Check if this memory address is marked writable to the process. + /// + /// @return + /// true if this memory address is marked writable + //------------------------------------------------------------------ + bool IsWritable(); + + //------------------------------------------------------------------ + /// Check if this memory address is marked executable to the process. + /// + /// @return + /// true if this memory address is marked executable + //------------------------------------------------------------------ + bool IsExecutable(); + + //------------------------------------------------------------------ + /// Check if this memory address is mapped into the process address + /// space. + /// + /// @return + /// true if this memory address is in the process address space. + //------------------------------------------------------------------ + bool IsMapped(); + + //------------------------------------------------------------------ + /// Returns the name of the memory region mapped at the given + /// address. + /// + /// @return + /// In case of memory mapped files it is the absolute path of + /// the file otherwise it is a name associated with the memory + /// region. If no name can be determined the returns nullptr. + //------------------------------------------------------------------ + const char *GetName(); + + bool operator==(const lldb::SBMemoryRegionInfo &rhs) const; + + bool operator!=(const lldb::SBMemoryRegionInfo &rhs) const; + + bool GetDescription(lldb::SBStream &description); + +private: + friend class SBProcess; + friend class SBMemoryRegionInfoList; + + lldb_private::MemoryRegionInfo &ref(); + + const lldb_private::MemoryRegionInfo &ref() const; + + SBMemoryRegionInfo(const lldb_private::MemoryRegionInfo *lldb_object_ptr); + + lldb::MemoryRegionInfoUP m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBMemoryRegionInfo_h_ diff --git a/include/lldb/API/SBMemoryRegionInfoList.h b/include/lldb/API/SBMemoryRegionInfoList.h new file mode 100644 index 000000000..883a2224c --- /dev/null +++ b/include/lldb/API/SBMemoryRegionInfoList.h @@ -0,0 +1,50 @@ +//===-- SBMemoryRegionInfoList.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_SBMemoryRegionInfoList_h_ +#define LLDB_SBMemoryRegionInfoList_h_ + +#include "lldb/API/SBDefines.h" + +class MemoryRegionInfoListImpl; + +namespace lldb { + +class LLDB_API SBMemoryRegionInfoList { +public: + SBMemoryRegionInfoList(); + + SBMemoryRegionInfoList(const lldb::SBMemoryRegionInfoList &rhs); + + const SBMemoryRegionInfoList &operator=(const SBMemoryRegionInfoList &rhs); + + ~SBMemoryRegionInfoList(); + + uint32_t GetSize() const; + + bool GetMemoryRegionAtIndex(uint32_t idx, SBMemoryRegionInfo ®ion_info); + + void Append(lldb::SBMemoryRegionInfo ®ion); + + void Append(lldb::SBMemoryRegionInfoList ®ion_list); + + void Clear(); + +protected: + const MemoryRegionInfoListImpl *operator->() const; + + const MemoryRegionInfoListImpl &operator*() const; + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBMemoryRegionInfoList_h_ diff --git a/include/lldb/API/SBModule.h b/include/lldb/API/SBModule.h new file mode 100644 index 000000000..bcc3997a2 --- /dev/null +++ b/include/lldb/API/SBModule.h @@ -0,0 +1,316 @@ +//===-- SBModule.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBModule_h_ +#define LLDB_SBModule_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBSection.h" +#include "lldb/API/SBSymbolContext.h" +#include "lldb/API/SBValueList.h" + +namespace lldb { + +class LLDB_API SBModule { +public: + SBModule(); + + SBModule(const SBModule &rhs); + + SBModule(const SBModuleSpec &module_spec); + + const SBModule &operator=(const SBModule &rhs); + + SBModule(lldb::SBProcess &process, lldb::addr_t header_addr); + + ~SBModule(); + + bool IsValid() const; + + void Clear(); + + //------------------------------------------------------------------ + /// Get const accessor for the module file specification. + /// + /// This function returns the file for the module on the host system + /// that is running LLDB. This can differ from the path on the + /// platform since we might be doing remote debugging. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec GetFileSpec() const; + + //------------------------------------------------------------------ + /// Get accessor for the module platform file specification. + /// + /// Platform file refers to the path of the module as it is known on + /// the remote system on which it is being debugged. For local + /// debugging this is always the same as Module::GetFileSpec(). But + /// remote debugging might mention a file '/usr/lib/liba.dylib' + /// which might be locally downloaded and cached. In this case the + /// platform file could be something like: + /// '/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib' + /// The file could also be cached in a local developer kit directory. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec GetPlatformFileSpec() const; + + bool SetPlatformFileSpec(const lldb::SBFileSpec &platform_file); + + //------------------------------------------------------------------ + /// Get accessor for the remote install path for a module. + /// + /// When debugging to a remote platform by connecting to a remote + /// platform, the install path of the module can be set. If the + /// install path is set, every time the process is about to launch + /// the target will install this module on the remote platform prior + /// to launching. + /// + /// @return + /// A file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec GetRemoteInstallFileSpec(); + + //------------------------------------------------------------------ + /// Set accessor for the remote install path for a module. + /// + /// When debugging to a remote platform by connecting to a remote + /// platform, the install path of the module can be set. If the + /// install path is set, every time the process is about to launch + /// the target will install this module on the remote platform prior + /// to launching. + /// + /// If \a file specifies a full path to an install location, the + /// module will be installed to this path. If the path is relative + /// (no directory specified, or the path is partial like "usr/lib" + /// or "./usr/lib", then the install path will be resolved using + /// the platform's current working directory as the base path. + /// + /// @param[in] file + /// A file specification object. + //------------------------------------------------------------------ + bool SetRemoteInstallFileSpec(lldb::SBFileSpec &file); + + lldb::ByteOrder GetByteOrder(); + + uint32_t GetAddressByteSize(); + + const char *GetTriple(); + + const uint8_t *GetUUIDBytes() const; + + const char *GetUUIDString() const; + + bool operator==(const lldb::SBModule &rhs) const; + + bool operator!=(const lldb::SBModule &rhs) const; + + lldb::SBSection FindSection(const char *sect_name); + + lldb::SBAddress ResolveFileAddress(lldb::addr_t vm_addr); + + lldb::SBSymbolContext + ResolveSymbolContextForAddress(const lldb::SBAddress &addr, + uint32_t resolve_scope); + + bool GetDescription(lldb::SBStream &description); + + uint32_t GetNumCompileUnits(); + + lldb::SBCompileUnit GetCompileUnitAtIndex(uint32_t); + + size_t GetNumSymbols(); + + lldb::SBSymbol GetSymbolAtIndex(size_t idx); + + lldb::SBSymbol FindSymbol(const char *name, + lldb::SymbolType type = eSymbolTypeAny); + + lldb::SBSymbolContextList FindSymbols(const char *name, + lldb::SymbolType type = eSymbolTypeAny); + + size_t GetNumSections(); + + lldb::SBSection GetSectionAtIndex(size_t idx); + //------------------------------------------------------------------ + /// Find functions by name. + /// + /// @param[in] name + /// The name of the function we are looking for. + /// + /// @param[in] name_type_mask + /// A logical OR of one or more FunctionNameType enum bits that + /// indicate what kind of names should be used when doing the + /// lookup. Bits include fully qualified names, base names, + /// C++ methods, or ObjC selectors. + /// See FunctionNameType for more details. + /// + /// @return + /// A lldb::SBSymbolContextList that gets filled in with all of + /// the symbol contexts for all the matches. + //------------------------------------------------------------------ + lldb::SBSymbolContextList + FindFunctions(const char *name, + uint32_t name_type_mask = lldb::eFunctionNameTypeAny); + + //------------------------------------------------------------------ + /// Find global and static variables by name. + /// + /// @param[in] target + /// A valid SBTarget instance representing the debuggee. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a max_matches. + /// + /// @return + /// A list of matched variables in an SBValueList. + //------------------------------------------------------------------ + lldb::SBValueList FindGlobalVariables(lldb::SBTarget &target, + const char *name, uint32_t max_matches); + + //------------------------------------------------------------------ + /// Find the first global (or static) variable by name. + /// + /// @param[in] target + /// A valid SBTarget instance representing the debuggee. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @return + /// An SBValue that gets filled in with the found variable (if any). + //------------------------------------------------------------------ + lldb::SBValue FindFirstGlobalVariable(lldb::SBTarget &target, + const char *name); + + lldb::SBType FindFirstType(const char *name); + + lldb::SBTypeList FindTypes(const char *type); + + //------------------------------------------------------------------ + /// Get a type using its type ID. + /// + /// Each symbol file reader will assign different user IDs to their + /// types, but it is sometimes useful when debugging type issues to + /// be able to grab a type using its type ID. + /// + /// For DWARF debug info, the type ID is the DIE offset. + /// + /// @param[in] uid + /// The type user ID. + /// + /// @return + /// An SBType for the given type ID, or an empty SBType if the + /// type was not found. + //------------------------------------------------------------------ + lldb::SBType GetTypeByID(lldb::user_id_t uid); + + lldb::SBType GetBasicType(lldb::BasicType type); + + //------------------------------------------------------------------ + /// Get all types matching \a type_mask from debug info in this + /// module. + /// + /// @param[in] type_mask + /// A bitfield that consists of one or more bits logically OR'ed + /// together from the lldb::TypeClass enumeration. This allows + /// you to request only structure types, or only class, struct + /// and union types. Passing in lldb::eTypeClassAny will return + /// all types found in the debug information for this module. + /// + /// @return + /// A list of types in this module that match \a type_mask + //------------------------------------------------------------------ + lldb::SBTypeList GetTypes(uint32_t type_mask = lldb::eTypeClassAny); + + //------------------------------------------------------------------ + /// Get the module version numbers. + /// + /// Many object files have a set of version numbers that describe + /// the version of the executable or shared library. Typically there + /// are major, minor and build, but there may be more. This function + /// will extract the versions from object files if they are available. + /// + /// If \a versions is NULL, or if \a num_versions is 0, the return + /// value will indicate how many version numbers are available in + /// this object file. Then a subsequent call can be made to this + /// function with a value of \a versions and \a num_versions that + /// has enough storage to store some or all version numbers. + /// + /// @param[out] versions + /// A pointer to an array of uint32_t types that is \a num_versions + /// long. If this value is NULL, the return value will indicate + /// how many version numbers are required for a subsequent call + /// to this function so that all versions can be retrieved. If + /// the value is non-NULL, then at most \a num_versions of the + /// existing versions numbers will be filled into \a versions. + /// If there is no version information available, \a versions + /// will be filled with \a num_versions UINT32_MAX values + /// and zero will be returned. + /// + /// @param[in] num_versions + /// The maximum number of entries to fill into \a versions. If + /// this value is zero, then the return value will indicate + /// how many version numbers there are in total so another call + /// to this function can be make with adequate storage in + /// \a versions to get all of the version numbers. If \a + /// num_versions is less than the actual number of version + /// numbers in this object file, only \a num_versions will be + /// filled into \a versions (if \a versions is non-NULL). + /// + /// @return + /// This function always returns the number of version numbers + /// that this object file has regardless of the number of + /// version numbers that were copied into \a versions. + //------------------------------------------------------------------ + uint32_t GetVersion(uint32_t *versions, uint32_t num_versions); + + //------------------------------------------------------------------ + /// Get accessor for the symbol file specification. + /// + /// When debugging an object file an additional debug information can + /// be provided in separate file. Therefore if you debugging something + /// like '/usr/lib/liba.dylib' then debug information can be located + /// in folder like '/usr/lib/liba.dylib.dSYM/'. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec GetSymbolFileSpec() const; + + lldb::SBAddress GetObjectFileHeaderAddress() const; + +private: + friend class SBAddress; + friend class SBFrame; + friend class SBSection; + friend class SBSymbolContext; + friend class SBTarget; + + explicit SBModule(const lldb::ModuleSP &module_sp); + + ModuleSP GetSP() const; + + void SetSP(const ModuleSP &module_sp); + + lldb::ModuleSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBModule_h_ diff --git a/include/lldb/API/SBModuleSpec.h b/include/lldb/API/SBModuleSpec.h new file mode 100644 index 000000000..1a862703a --- /dev/null +++ b/include/lldb/API/SBModuleSpec.h @@ -0,0 +1,125 @@ +//===-- SBModuleSpec.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBModuleSpec_h_ +#define LLDB_SBModuleSpec_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFileSpec.h" + +namespace lldb { + +class LLDB_API SBModuleSpec { +public: + SBModuleSpec(); + + SBModuleSpec(const SBModuleSpec &rhs); + + ~SBModuleSpec(); + + const SBModuleSpec &operator=(const SBModuleSpec &rhs); + + bool IsValid() const; + + void Clear(); + + //------------------------------------------------------------------ + /// Get const accessor for the module file. + /// + /// This function returns the file for the module on the host system + /// that is running LLDB. This can differ from the path on the + /// platform since we might be doing remote debugging. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec GetFileSpec(); + + void SetFileSpec(const lldb::SBFileSpec &fspec); + + //------------------------------------------------------------------ + /// Get accessor for the module platform file. + /// + /// Platform file refers to the path of the module as it is known on + /// the remote system on which it is being debugged. For local + /// debugging this is always the same as Module::GetFileSpec(). But + /// remote debugging might mention a file '/usr/lib/liba.dylib' + /// which might be locally downloaded and cached. In this case the + /// platform file could be something like: + /// '/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib' + /// The file could also be cached in a local developer kit directory. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec GetPlatformFileSpec(); + + void SetPlatformFileSpec(const lldb::SBFileSpec &fspec); + + lldb::SBFileSpec GetSymbolFileSpec(); + + void SetSymbolFileSpec(const lldb::SBFileSpec &fspec); + + const char *GetObjectName(); + + void SetObjectName(const char *name); + + const char *GetTriple(); + + void SetTriple(const char *triple); + + const uint8_t *GetUUIDBytes(); + + size_t GetUUIDLength(); + + bool SetUUIDBytes(const uint8_t *uuid, size_t uuid_len); + + bool GetDescription(lldb::SBStream &description); + +private: + friend class SBModuleSpecList; + friend class SBModule; + friend class SBTarget; + + std::unique_ptr m_opaque_ap; +}; + +class SBModuleSpecList { +public: + SBModuleSpecList(); + + SBModuleSpecList(const SBModuleSpecList &rhs); + + ~SBModuleSpecList(); + + SBModuleSpecList &operator=(const SBModuleSpecList &rhs); + + static SBModuleSpecList GetModuleSpecifications(const char *path); + + void Append(const SBModuleSpec &spec); + + void Append(const SBModuleSpecList &spec_list); + + SBModuleSpec FindFirstMatchingSpec(const SBModuleSpec &match_spec); + + SBModuleSpecList FindMatchingSpecs(const SBModuleSpec &match_spec); + + size_t GetSize(); + + SBModuleSpec GetSpecAtIndex(size_t i); + + bool GetDescription(lldb::SBStream &description); + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBModuleSpec_h_ diff --git a/include/lldb/API/SBPlatform.h b/include/lldb/API/SBPlatform.h new file mode 100644 index 000000000..952e31066 --- /dev/null +++ b/include/lldb/API/SBPlatform.h @@ -0,0 +1,167 @@ +//===-- SBPlatform.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_SBPlatform_h_ +#define LLDB_SBPlatform_h_ + +#include "lldb/API/SBDefines.h" + +#include + +struct PlatformConnectOptions; +struct PlatformShellCommand; + +namespace lldb { + +class SBLaunchInfo; + +class LLDB_API SBPlatformConnectOptions { +public: + SBPlatformConnectOptions(const char *url); + + SBPlatformConnectOptions(const SBPlatformConnectOptions &rhs); + + ~SBPlatformConnectOptions(); + + void operator=(const SBPlatformConnectOptions &rhs); + + const char *GetURL(); + + void SetURL(const char *url); + + bool GetRsyncEnabled(); + + void EnableRsync(const char *options, const char *remote_path_prefix, + bool omit_remote_hostname); + + void DisableRsync(); + + const char *GetLocalCacheDirectory(); + + void SetLocalCacheDirectory(const char *path); + +protected: + PlatformConnectOptions *m_opaque_ptr; +}; + +class LLDB_API SBPlatformShellCommand { +public: + SBPlatformShellCommand(const char *shell_command); + + SBPlatformShellCommand(const SBPlatformShellCommand &rhs); + + ~SBPlatformShellCommand(); + + void Clear(); + + const char *GetCommand(); + + void SetCommand(const char *shell_command); + + const char *GetWorkingDirectory(); + + void SetWorkingDirectory(const char *path); + + uint32_t GetTimeoutSeconds(); + + void SetTimeoutSeconds(uint32_t sec); + + int GetSignal(); + + int GetStatus(); + + const char *GetOutput(); + +protected: + friend class SBPlatform; + + PlatformShellCommand *m_opaque_ptr; +}; + +class LLDB_API SBPlatform { +public: + SBPlatform(); + + SBPlatform(const char *platform_name); + + ~SBPlatform(); + + bool IsValid() const; + + void Clear(); + + const char *GetWorkingDirectory(); + + bool SetWorkingDirectory(const char *path); + + const char *GetName(); + + SBError ConnectRemote(SBPlatformConnectOptions &connect_options); + + void DisconnectRemote(); + + bool IsConnected(); + + //---------------------------------------------------------------------- + // The following functions will work if the platform is connected + //---------------------------------------------------------------------- + const char *GetTriple(); + + const char *GetHostname(); + + const char *GetOSBuild(); + + const char *GetOSDescription(); + + uint32_t GetOSMajorVersion(); + + uint32_t GetOSMinorVersion(); + + uint32_t GetOSUpdateVersion(); + + SBError Put(SBFileSpec &src, SBFileSpec &dst); + + SBError Get(SBFileSpec &src, SBFileSpec &dst); + + SBError Install(SBFileSpec &src, SBFileSpec &dst); + + SBError Run(SBPlatformShellCommand &shell_command); + + SBError Launch(SBLaunchInfo &launch_info); + + SBError Kill(const lldb::pid_t pid); + + SBError + MakeDirectory(const char *path, + uint32_t file_permissions = eFilePermissionsDirectoryDefault); + + uint32_t GetFilePermissions(const char *path); + + SBError SetFilePermissions(const char *path, uint32_t file_permissions); + + SBUnixSignals GetUnixSignals() const; + +protected: + friend class SBDebugger; + friend class SBTarget; + + lldb::PlatformSP GetSP() const; + + void SetSP(const lldb::PlatformSP &platform_sp); + + SBError ExecuteConnected( + const std::function + &func); + + lldb::PlatformSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBPlatform_h_ diff --git a/include/lldb/API/SBProcess.h b/include/lldb/API/SBProcess.h new file mode 100644 index 000000000..d57d5ce04 --- /dev/null +++ b/include/lldb/API/SBProcess.h @@ -0,0 +1,406 @@ +//===-- SBProcess.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBProcess_h_ +#define LLDB_SBProcess_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBQueue.h" +#include "lldb/API/SBTarget.h" +#include + +namespace lldb { + +class SBEvent; + +class LLDB_API SBProcess { +public: + //------------------------------------------------------------------ + /// Broadcaster event bits definitions. + //------------------------------------------------------------------ + FLAGS_ANONYMOUS_ENUM(){eBroadcastBitStateChanged = (1 << 0), + eBroadcastBitInterrupt = (1 << 1), + eBroadcastBitSTDOUT = (1 << 2), + eBroadcastBitSTDERR = (1 << 3), + eBroadcastBitProfileData = (1 << 4), + eBroadcastBitStructuredData = (1 << 5)}; + + SBProcess(); + + SBProcess(const lldb::SBProcess &rhs); + + const lldb::SBProcess &operator=(const lldb::SBProcess &rhs); + + SBProcess(const lldb::ProcessSP &process_sp); + + ~SBProcess(); + + static const char *GetBroadcasterClassName(); + + const char *GetPluginName(); + + // DEPRECATED: use GetPluginName() + const char *GetShortPluginName(); + + void Clear(); + + bool IsValid() const; + + lldb::SBTarget GetTarget() const; + + lldb::ByteOrder GetByteOrder() const; + + size_t PutSTDIN(const char *src, size_t src_len); + + size_t GetSTDOUT(char *dst, size_t dst_len) const; + + size_t GetSTDERR(char *dst, size_t dst_len) const; + + size_t GetAsyncProfileData(char *dst, size_t dst_len) const; + + void ReportEventState(const lldb::SBEvent &event, FILE *out) const; + + void AppendEventStateReport(const lldb::SBEvent &event, + lldb::SBCommandReturnObject &result); + + //------------------------------------------------------------------ + /// Remote connection related functions. These will fail if the + /// process is not in eStateConnected. They are intended for use + /// when connecting to an externally managed debugserver instance. + //------------------------------------------------------------------ + bool RemoteAttachToProcessWithID(lldb::pid_t pid, lldb::SBError &error); + + bool RemoteLaunch(char const **argv, char const **envp, + const char *stdin_path, const char *stdout_path, + const char *stderr_path, const char *working_directory, + uint32_t launch_flags, bool stop_at_entry, + lldb::SBError &error); + + //------------------------------------------------------------------ + // Thread related functions + //------------------------------------------------------------------ + uint32_t GetNumThreads(); + + lldb::SBThread GetThreadAtIndex(size_t index); + + lldb::SBThread GetThreadByID(lldb::tid_t sb_thread_id); + + lldb::SBThread GetThreadByIndexID(uint32_t index_id); + + lldb::SBThread GetSelectedThread() const; + + //------------------------------------------------------------------ + // Function for lazily creating a thread using the current OS + // plug-in. This function will be removed in the future when there + // are APIs to create SBThread objects through the interface and add + // them to the process through the SBProcess API. + //------------------------------------------------------------------ + lldb::SBThread CreateOSPluginThread(lldb::tid_t tid, lldb::addr_t context); + + bool SetSelectedThread(const lldb::SBThread &thread); + + bool SetSelectedThreadByID(lldb::tid_t tid); + + bool SetSelectedThreadByIndexID(uint32_t index_id); + + //------------------------------------------------------------------ + // Queue related functions + //------------------------------------------------------------------ + uint32_t GetNumQueues(); + + lldb::SBQueue GetQueueAtIndex(size_t index); + + //------------------------------------------------------------------ + // Stepping related functions + //------------------------------------------------------------------ + + lldb::StateType GetState(); + + int GetExitStatus(); + + const char *GetExitDescription(); + + //------------------------------------------------------------------ + /// Gets the process ID + /// + /// Returns the process identifier for the process as it is known + /// on the system on which the process is running. For unix systems + /// this is typically the same as if you called "getpid()" in the + /// process. + /// + /// @return + /// Returns LLDB_INVALID_PROCESS_ID if this object does not + /// contain a valid process object, or if the process has not + /// been launched. Returns a valid process ID if the process is + /// valid. + //------------------------------------------------------------------ + lldb::pid_t GetProcessID(); + + //------------------------------------------------------------------ + /// Gets the unique ID associated with this process object + /// + /// Unique IDs start at 1 and increment up with each new process + /// instance. Since starting a process on a system might always + /// create a process with the same process ID, there needs to be a + /// way to tell two process instances apart. + /// + /// @return + /// Returns a non-zero integer ID if this object contains a + /// valid process object, zero if this object does not contain + /// a valid process object. + //------------------------------------------------------------------ + uint32_t GetUniqueID(); + + uint32_t GetAddressByteSize() const; + + lldb::SBError Destroy(); + + lldb::SBError Continue(); + + lldb::SBError Stop(); + + lldb::SBError Kill(); + + lldb::SBError Detach(); + + lldb::SBError Detach(bool keep_stopped); + + lldb::SBError Signal(int signal); + + lldb::SBUnixSignals GetUnixSignals(); + + void SendAsyncInterrupt(); + + uint32_t GetStopID(bool include_expression_stops = false); + + //------------------------------------------------------------------ + /// Gets the stop event corresponding to stop ID. + // + /// Note that it wasn't fully implemented and tracks only the stop + /// event for the last natural stop ID. + /// + /// @param [in] stop_id + /// The ID of the stop event to return. + /// + /// @return + /// The stop event corresponding to stop ID. + //------------------------------------------------------------------ + lldb::SBEvent GetStopEventForStopID(uint32_t stop_id); + + size_t ReadMemory(addr_t addr, void *buf, size_t size, lldb::SBError &error); + + size_t WriteMemory(addr_t addr, const void *buf, size_t size, + lldb::SBError &error); + + size_t ReadCStringFromMemory(addr_t addr, void *buf, size_t size, + lldb::SBError &error); + + uint64_t ReadUnsignedFromMemory(addr_t addr, uint32_t byte_size, + lldb::SBError &error); + + lldb::addr_t ReadPointerFromMemory(addr_t addr, lldb::SBError &error); + + // Events + static lldb::StateType GetStateFromEvent(const lldb::SBEvent &event); + + static bool GetRestartedFromEvent(const lldb::SBEvent &event); + + static size_t GetNumRestartedReasonsFromEvent(const lldb::SBEvent &event); + + static const char * + GetRestartedReasonAtIndexFromEvent(const lldb::SBEvent &event, size_t idx); + + static lldb::SBProcess GetProcessFromEvent(const lldb::SBEvent &event); + + static bool GetInterruptedFromEvent(const lldb::SBEvent &event); + + static lldb::SBStructuredData + GetStructuredDataFromEvent(const lldb::SBEvent &event); + + static bool EventIsProcessEvent(const lldb::SBEvent &event); + + static bool EventIsStructuredDataEvent(const lldb::SBEvent &event); + + lldb::SBBroadcaster GetBroadcaster() const; + + static const char *GetBroadcasterClass(); + + bool GetDescription(lldb::SBStream &description); + + //------------------------------------------------------------------ + /// Start Tracing with the given SBTraceOptions. + /// + /// @param[in] options + /// Class containing trace options like trace buffer size, meta + /// data buffer size, TraceType and any custom parameters + /// {formatted as a JSON Dictionary}. In case of errors in + /// formatting, an error would be reported. + /// It must be noted that tracing options such as buffer sizes + /// or other custom parameters passed maybe invalid for some + /// trace technologies. In such cases the trace implementations + /// could choose to either throw an error or could round off to + /// the nearest valid options to start tracing if the passed + /// value is not supported. To obtain the actual used trace + /// options please use the GetTraceConfig API. For the custom + /// parameters, only the parameters recognized by the target + /// would be used and others would be ignored. + /// + /// @param[out] error + /// An error explaining what went wrong. + /// + /// @return + /// A SBTrace instance, which should be used + /// to get the trace data or other trace related operations. + //------------------------------------------------------------------ + lldb::SBTrace StartTrace(SBTraceOptions &options, lldb::SBError &error); + + uint32_t GetNumSupportedHardwareWatchpoints(lldb::SBError &error) const; + + //------------------------------------------------------------------ + /// Load a shared library into this process. + /// + /// @param[in] remote_image_spec + /// The path for the shared library on the target what you want + /// to load. + /// + /// @param[out] error + /// An error object that gets filled in with any errors that + /// might occur when trying to load the shared library. + /// + /// @return + /// A token that represents the shared library that can be + /// later used to unload the shared library. A value of + /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared + /// library can't be opened. + //------------------------------------------------------------------ + uint32_t LoadImage(lldb::SBFileSpec &remote_image_spec, lldb::SBError &error); + + //------------------------------------------------------------------ + /// Load a shared library into this process. + /// + /// @param[in] local_image_spec + /// The file spec that points to the shared library that you + /// want to load if the library is located on the host. The + /// library will be copied over to the location specified by + /// remote_image_spec or into the current working directory with + /// the same filename if the remote_image_spec isn't specified. + /// + /// @param[in] remote_image_spec + /// If local_image_spec is specified then the location where the + /// library should be copied over from the host. If + /// local_image_spec isn't specified, then the path for the + /// shared library on the target what you want to load. + /// + /// @param[out] error + /// An error object that gets filled in with any errors that + /// might occur when trying to load the shared library. + /// + /// @return + /// A token that represents the shared library that can be + /// later used to unload the shared library. A value of + /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared + /// library can't be opened. + //------------------------------------------------------------------ + uint32_t LoadImage(const lldb::SBFileSpec &local_image_spec, + const lldb::SBFileSpec &remote_image_spec, + lldb::SBError &error); + + lldb::SBError UnloadImage(uint32_t image_token); + + lldb::SBError SendEventData(const char *data); + + //------------------------------------------------------------------ + /// Return the number of different thread-origin extended backtraces + /// this process can support. + /// + /// When the process is stopped and you have an SBThread, lldb may be + /// able to show a backtrace of when that thread was originally created, + /// or the work item was enqueued to it (in the case of a libdispatch + /// queue). + /// + /// @return + /// The number of thread-origin extended backtrace types that may be + /// available. + //------------------------------------------------------------------ + uint32_t GetNumExtendedBacktraceTypes(); + + //------------------------------------------------------------------ + /// Return the name of one of the thread-origin extended backtrace + /// methods. + /// + /// @param [in] idx + /// The index of the name to return. They will be returned in + /// the order that the user will most likely want to see them. + /// e.g. if the type at index 0 is not available for a thread, + /// see if the type at index 1 provides an extended backtrace. + /// + /// @return + /// The name at that index. + //------------------------------------------------------------------ + const char *GetExtendedBacktraceTypeAtIndex(uint32_t idx); + + lldb::SBThreadCollection GetHistoryThreads(addr_t addr); + + bool IsInstrumentationRuntimePresent(InstrumentationRuntimeType type); + + /// Save the state of the process in a core file (or mini dump on Windows). + lldb::SBError SaveCore(const char *file_name); + + //------------------------------------------------------------------ + /// Query the address load_addr and store the details of the memory + /// region that contains it in the supplied SBMemoryRegionInfo object. + /// To iterate over all memory regions use GetMemoryRegionList. + /// + /// @param[in] load_addr + /// The address to be queried. + /// + /// @param[out] region_info + /// A reference to an SBMemoryRegionInfo object that will contain + /// the details of the memory region containing load_addr. + /// + /// @return + /// An error object describes any errors that occurred while + /// querying load_addr. + //------------------------------------------------------------------ + lldb::SBError GetMemoryRegionInfo(lldb::addr_t load_addr, + lldb::SBMemoryRegionInfo ®ion_info); + + //------------------------------------------------------------------ + /// Return the list of memory regions within the process. + /// + /// @return + /// A list of all witin the process memory regions. + //------------------------------------------------------------------ + lldb::SBMemoryRegionInfoList GetMemoryRegions(); + +protected: + friend class SBAddress; + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBCommandInterpreter; + friend class SBDebugger; + friend class SBExecutionContext; + friend class SBFunction; + friend class SBModule; + friend class SBTarget; + friend class SBThread; + friend class SBValue; + friend class lldb_private::QueueImpl; + + lldb::ProcessSP GetSP() const; + + void SetSP(const lldb::ProcessSP &process_sp); + + lldb::ProcessWP m_opaque_wp; +}; + +} // namespace lldb + +#endif // LLDB_SBProcess_h_ diff --git a/include/lldb/API/SBQueue.h b/include/lldb/API/SBQueue.h new file mode 100644 index 000000000..53612c0a1 --- /dev/null +++ b/include/lldb/API/SBQueue.h @@ -0,0 +1,72 @@ +//===-- SBQueue.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_SBQueue_h_ +#define LLDB_SBQueue_h_ + +#include + +#include "lldb/API/SBDefines.h" +#include "lldb/lldb-forward.h" + +namespace lldb { + +class LLDB_API SBQueue { +public: + SBQueue(); + + SBQueue(const QueueSP &queue_sp); + + SBQueue(const SBQueue &rhs); + + const SBQueue &operator=(const lldb::SBQueue &rhs); + + ~SBQueue(); + + bool IsValid() const; + + void Clear(); + + lldb::SBProcess GetProcess(); + + lldb::queue_id_t GetQueueID() const; + + const char *GetName() const; + + uint32_t GetIndexID() const; + + uint32_t GetNumThreads(); + + lldb::SBThread GetThreadAtIndex(uint32_t); + + uint32_t GetNumPendingItems(); + + lldb::SBQueueItem GetPendingItemAtIndex(uint32_t); + + uint32_t GetNumRunningItems(); + + lldb::QueueKind GetKind(); + +protected: + friend class SBProcess; + friend class SBThread; + + void SetQueue(const lldb::QueueSP &queue_sp); + + void FetchThreads(); + + void FetchItems(); + +private: + std::shared_ptr m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBQueue_h_ diff --git a/include/lldb/API/SBQueueItem.h b/include/lldb/API/SBQueueItem.h new file mode 100644 index 000000000..78ca3ba02 --- /dev/null +++ b/include/lldb/API/SBQueueItem.h @@ -0,0 +1,48 @@ +//===-- SBQueueItem.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_SBQueueItem_h_ +#define LLDB_SBQueueItem_h_ + +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBQueueItem { +public: + SBQueueItem(); + + SBQueueItem(const lldb::QueueItemSP &queue_item_sp); + + ~SBQueueItem(); + + bool IsValid() const; + + void Clear(); + + lldb::QueueItemKind GetKind() const; + + void SetKind(lldb::QueueItemKind kind); + + lldb::SBAddress GetAddress() const; + + void SetAddress(lldb::SBAddress addr); + + void SetQueueItem(const lldb::QueueItemSP &queue_item_sp); + + SBThread GetExtendedBacktraceThread(const char *type); + +private: + lldb::QueueItemSP m_queue_item_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBQueueItem_h_ diff --git a/include/lldb/API/SBSection.h b/include/lldb/API/SBSection.h new file mode 100644 index 000000000..ffd8bf7c9 --- /dev/null +++ b/include/lldb/API/SBSection.h @@ -0,0 +1,104 @@ +//===-- SBSection.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBSection_h_ +#define LLDB_SBSection_h_ + +#include "lldb/API/SBData.h" +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBSection { +public: + SBSection(); + + SBSection(const lldb::SBSection &rhs); + + ~SBSection(); + + const lldb::SBSection &operator=(const lldb::SBSection &rhs); + + bool IsValid() const; + + const char *GetName(); + + lldb::SBSection GetParent(); + + lldb::SBSection FindSubSection(const char *sect_name); + + size_t GetNumSubSections(); + + lldb::SBSection GetSubSectionAtIndex(size_t idx); + + lldb::addr_t GetFileAddress(); + + lldb::addr_t GetLoadAddress(lldb::SBTarget &target); + + lldb::addr_t GetByteSize(); + + uint64_t GetFileOffset(); + + uint64_t GetFileByteSize(); + + lldb::SBData GetSectionData(); + + lldb::SBData GetSectionData(uint64_t offset, uint64_t size); + + SectionType GetSectionType(); + + //------------------------------------------------------------------ + /// Gets the permissions (RWX) of the section of the object file + /// + /// Returns a mask of bits of enum lldb::Permissions for this section. + /// Sections for which permissions are not defined, 0 is returned for + /// them. The binary representation of this value corresponds to [XRW] + /// i.e. for a section having read and execute permissions, the value + /// returned is 6 + /// + /// @return + /// Returns an unsigned value for Permissions for the section. + //------------------------------------------------------------------ + uint32_t + GetPermissions() const; + + //------------------------------------------------------------------ + /// Return the size of a target's byte represented by this section + /// in numbers of host bytes. Note that certain architectures have + /// varying minimum addressable unit (i.e. byte) size for their + /// CODE or DATA buses. + /// + /// @return + /// The number of host (8-bit) bytes needed to hold a target byte + //------------------------------------------------------------------ + uint32_t GetTargetByteSize(); + + bool operator==(const lldb::SBSection &rhs); + + bool operator!=(const lldb::SBSection &rhs); + + bool GetDescription(lldb::SBStream &description); + +private: + friend class SBAddress; + friend class SBModule; + friend class SBTarget; + + SBSection(const lldb::SectionSP §ion_sp); + + lldb::SectionSP GetSP() const; + + void SetSP(const lldb::SectionSP §ion_sp); + + lldb::SectionWP m_opaque_wp; +}; + +} // namespace lldb + +#endif // LLDB_SBSection_h_ diff --git a/include/lldb/API/SBSourceManager.h b/include/lldb/API/SBSourceManager.h new file mode 100644 index 000000000..6f1c49504 --- /dev/null +++ b/include/lldb/API/SBSourceManager.h @@ -0,0 +1,50 @@ +//===-- SBSourceManager.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBSourceManager_h_ +#define LLDB_SBSourceManager_h_ + +#include "lldb/API/SBDefines.h" + +#include + +namespace lldb { + +class LLDB_API SBSourceManager { +public: + SBSourceManager(const SBDebugger &debugger); + SBSourceManager(const SBTarget &target); + SBSourceManager(const SBSourceManager &rhs); + + ~SBSourceManager(); + + const lldb::SBSourceManager &operator=(const lldb::SBSourceManager &rhs); + + size_t DisplaySourceLinesWithLineNumbers( + const lldb::SBFileSpec &file, uint32_t line, uint32_t context_before, + uint32_t context_after, const char *current_line_cstr, lldb::SBStream &s); + + size_t DisplaySourceLinesWithLineNumbersAndColumn( + const lldb::SBFileSpec &file, uint32_t line, uint32_t column, + uint32_t context_before, uint32_t context_after, + const char *current_line_cstr, lldb::SBStream &s); + +protected: + friend class SBCommandInterpreter; + friend class SBDebugger; + + SBSourceManager(lldb_private::SourceManager *source_manager); + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBSourceManager_h_ diff --git a/include/lldb/API/SBStream.h b/include/lldb/API/SBStream.h new file mode 100644 index 000000000..68fcae21c --- /dev/null +++ b/include/lldb/API/SBStream.h @@ -0,0 +1,104 @@ +//===-- SBStream.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBStream_h_ +#define LLDB_SBStream_h_ + +#include + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBStream { +public: + SBStream(); + + SBStream(SBStream &&rhs); + + ~SBStream(); + + bool IsValid() const; + + // If this stream is not redirected to a file, it will maintain a local + // cache for the stream data which can be accessed using this accessor. + const char *GetData(); + + // If this stream is not redirected to a file, it will maintain a local + // cache for the stream output whose length can be accessed using this + // accessor. + size_t GetSize(); + + void Printf(const char *format, ...) __attribute__((format(printf, 2, 3))); + + void RedirectToFile(const char *path, bool append); + + void RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership); + + void RedirectToFileDescriptor(int fd, bool transfer_fh_ownership); + + // If the stream is redirected to a file, forget about the file and if + // ownership of the file was transferred to this object, close the file. + // If the stream is backed by a local cache, clear this cache. + void Clear(); + +protected: + friend class SBAddress; + friend class SBBlock; + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBCommandReturnObject; + friend class SBCompileUnit; + friend class SBData; + friend class SBDebugger; + friend class SBDeclaration; + friend class SBEvent; + friend class SBFileSpec; + friend class SBFileSpecList; + friend class SBFrame; + friend class SBFunction; + friend class SBInstruction; + friend class SBInstructionList; + friend class SBLineEntry; + friend class SBMemoryRegionInfo; + friend class SBModule; + friend class SBModuleSpec; + friend class SBModuleSpecList; + friend class SBProcess; + friend class SBSection; + friend class SBSourceManager; + friend class SBStructuredData; + friend class SBSymbol; + friend class SBSymbolContext; + friend class SBSymbolContextList; + friend class SBTarget; + friend class SBThread; + friend class SBThreadPlan; + friend class SBType; + friend class SBTypeEnumMember; + friend class SBTypeMemberFunction; + friend class SBTypeMember; + friend class SBValue; + friend class SBWatchpoint; + + lldb_private::Stream *operator->(); + + lldb_private::Stream *get(); + + lldb_private::Stream &ref(); + +private: + DISALLOW_COPY_AND_ASSIGN(SBStream); + std::unique_ptr m_opaque_ap; + bool m_is_file; +}; + +} // namespace lldb + +#endif // LLDB_SBStream_h_ diff --git a/include/lldb/API/SBStringList.h b/include/lldb/API/SBStringList.h new file mode 100644 index 000000000..66b5172a0 --- /dev/null +++ b/include/lldb/API/SBStringList.h @@ -0,0 +1,62 @@ +//===-- SBStringList.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBStringList_h_ +#define LLDB_SBStringList_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBStringList { +public: + SBStringList(); + + SBStringList(const lldb::SBStringList &rhs); + + const SBStringList &operator=(const SBStringList &rhs); + + ~SBStringList(); + + bool IsValid() const; + + void AppendString(const char *str); + + void AppendList(const char **strv, int strc); + + void AppendList(const lldb::SBStringList &strings); + + uint32_t GetSize() const; + + const char *GetStringAtIndex(size_t idx); + + const char *GetStringAtIndex(size_t idx) const; + + void Clear(); + +protected: + friend class SBCommandInterpreter; + friend class SBDebugger; + friend class SBBreakpoint; + + SBStringList(const lldb_private::StringList *lldb_strings); + + void AppendList(const lldb_private::StringList &strings); + + const lldb_private::StringList *operator->() const; + + const lldb_private::StringList &operator*() const; + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBStringList_h_ diff --git a/include/lldb/API/SBStructuredData.h b/include/lldb/API/SBStructuredData.h new file mode 100644 index 000000000..f7a6469bb --- /dev/null +++ b/include/lldb/API/SBStructuredData.h @@ -0,0 +1,106 @@ +//===-- SBStructuredData.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SBStructuredData_h +#define SBStructuredData_h + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBModule.h" + +namespace lldb { + +class SBStructuredData { +public: + SBStructuredData(); + + SBStructuredData(const lldb::SBStructuredData &rhs); + + SBStructuredData(const lldb::EventSP &event_sp); + + ~SBStructuredData(); + + lldb::SBStructuredData &operator=(const lldb::SBStructuredData &rhs); + + bool IsValid() const; + + lldb::SBError SetFromJSON(lldb::SBStream &stream); + + void Clear(); + + lldb::SBError GetAsJSON(lldb::SBStream &stream) const; + + lldb::SBError GetDescription(lldb::SBStream &stream) const; + + //------------------------------------------------------------------ + /// Return the type of data in this data structure + //------------------------------------------------------------------ + lldb::StructuredDataType GetType() const; + + //------------------------------------------------------------------ + /// Return the size (i.e. number of elements) in this data structure + /// if it is an array or dictionary type. For other types, 0 will be + // returned. + //------------------------------------------------------------------ + size_t GetSize() const; + + //------------------------------------------------------------------ + /// Return the value corresponding to a key if this data structure + /// is a dictionary type. + //------------------------------------------------------------------ + lldb::SBStructuredData GetValueForKey(const char *key) const; + + //------------------------------------------------------------------ + /// Return the value corresponding to an index if this data structure + /// is array. + //------------------------------------------------------------------ + lldb::SBStructuredData GetItemAtIndex(size_t idx) const; + + //------------------------------------------------------------------ + /// Return the integer value if this data structure is an integer type. + //------------------------------------------------------------------ + uint64_t GetIntegerValue(uint64_t fail_value = 0) const; + + //------------------------------------------------------------------ + /// Return the floating point value if this data structure is a floating + /// type. + //------------------------------------------------------------------ + double GetFloatValue(double fail_value = 0.0) const; + + //------------------------------------------------------------------ + /// Return the boolean value if this data structure is a boolean type. + //------------------------------------------------------------------ + bool GetBooleanValue(bool fail_value = false) const; + + //------------------------------------------------------------------ + /// Provides the string value if this data structure is a string type. + /// + /// @param[out] dst + /// pointer where the string value will be written. In case it is null, + /// nothing will be written at @dst. + /// + /// @param[in] dst_len + /// max number of characters that can be written at @dst. In case it is + /// zero, nothing will be written at @dst. If this length is not enough + /// to write the complete string value, (dst_len-1) bytes of the string + /// value will be written at @dst followed by a null character. + /// + /// @return + /// Returns the byte size needed to completely write the string value at + /// @dst in all cases. + //------------------------------------------------------------------ + size_t GetStringValue(char *dst, size_t dst_len) const; + +protected: + friend class SBTraceOptions; + + StructuredDataImplUP m_impl_up; +}; +} // namespace lldb + +#endif /* SBStructuredData_h */ diff --git a/include/lldb/API/SBSymbol.h b/include/lldb/API/SBSymbol.h new file mode 100644 index 000000000..d17a4ccff --- /dev/null +++ b/include/lldb/API/SBSymbol.h @@ -0,0 +1,89 @@ +//===-- SBSymbol.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBSymbol_h_ +#define LLDB_SBSymbol_h_ + +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBInstructionList.h" +#include "lldb/API/SBTarget.h" + +namespace lldb { + +class LLDB_API SBSymbol { +public: + SBSymbol(); + + ~SBSymbol(); + + SBSymbol(const lldb::SBSymbol &rhs); + + const lldb::SBSymbol &operator=(const lldb::SBSymbol &rhs); + + bool IsValid() const; + + const char *GetName() const; + + const char *GetDisplayName() const; + + const char *GetMangledName() const; + + lldb::SBInstructionList GetInstructions(lldb::SBTarget target); + + lldb::SBInstructionList GetInstructions(lldb::SBTarget target, + const char *flavor_string); + + SBAddress GetStartAddress(); + + SBAddress GetEndAddress(); + + uint32_t GetPrologueByteSize(); + + SymbolType GetType(); + + bool operator==(const lldb::SBSymbol &rhs) const; + + bool operator!=(const lldb::SBSymbol &rhs) const; + + bool GetDescription(lldb::SBStream &description); + + //---------------------------------------------------------------------- + // Returns true if the symbol is externally visible in the module that + // it is defined in + //---------------------------------------------------------------------- + bool IsExternal(); + + //---------------------------------------------------------------------- + // Returns true if the symbol was synthetically generated from something + // other than the actual symbol table itself in the object file. + //---------------------------------------------------------------------- + bool IsSynthetic(); + +protected: + lldb_private::Symbol *get(); + + void reset(lldb_private::Symbol *); + +private: + friend class SBAddress; + friend class SBFrame; + friend class SBModule; + friend class SBSymbolContext; + + SBSymbol(lldb_private::Symbol *lldb_object_ptr); + + void SetSymbol(lldb_private::Symbol *lldb_object_ptr); + + lldb_private::Symbol *m_opaque_ptr; +}; + +} // namespace lldb + +#endif // LLDB_SBSymbol_h_ diff --git a/include/lldb/API/SBSymbolContext.h b/include/lldb/API/SBSymbolContext.h new file mode 100644 index 000000000..04ee15e8e --- /dev/null +++ b/include/lldb/API/SBSymbolContext.h @@ -0,0 +1,82 @@ +//===-- SBSymbolContext.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBSymbolContext_h_ +#define LLDB_SBSymbolContext_h_ + +#include "lldb/API/SBBlock.h" +#include "lldb/API/SBCompileUnit.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFunction.h" +#include "lldb/API/SBLineEntry.h" +#include "lldb/API/SBModule.h" +#include "lldb/API/SBSymbol.h" + +namespace lldb { + +class LLDB_API SBSymbolContext { +public: + SBSymbolContext(); + + SBSymbolContext(const lldb::SBSymbolContext &rhs); + + ~SBSymbolContext(); + + bool IsValid() const; + + const lldb::SBSymbolContext &operator=(const lldb::SBSymbolContext &rhs); + + lldb::SBModule GetModule(); + lldb::SBCompileUnit GetCompileUnit(); + lldb::SBFunction GetFunction(); + lldb::SBBlock GetBlock(); + lldb::SBLineEntry GetLineEntry(); + lldb::SBSymbol GetSymbol(); + + void SetModule(lldb::SBModule module); + void SetCompileUnit(lldb::SBCompileUnit compile_unit); + void SetFunction(lldb::SBFunction function); + void SetBlock(lldb::SBBlock block); + void SetLineEntry(lldb::SBLineEntry line_entry); + void SetSymbol(lldb::SBSymbol symbol); + + SBSymbolContext GetParentOfInlinedScope(const SBAddress &curr_frame_pc, + SBAddress &parent_frame_addr) const; + + bool GetDescription(lldb::SBStream &description); + +protected: + friend class SBAddress; + friend class SBFrame; + friend class SBModule; + friend class SBThread; + friend class SBTarget; + friend class SBSymbolContextList; + + lldb_private::SymbolContext *operator->() const; + + lldb_private::SymbolContext &operator*(); + + lldb_private::SymbolContext &ref(); + + const lldb_private::SymbolContext &operator*() const; + + lldb_private::SymbolContext *get() const; + + SBSymbolContext(const lldb_private::SymbolContext *sc_ptr); + + void SetSymbolContext(const lldb_private::SymbolContext *sc_ptr); + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBSymbolContext_h_ diff --git a/include/lldb/API/SBSymbolContextList.h b/include/lldb/API/SBSymbolContextList.h new file mode 100644 index 000000000..e7299dd53 --- /dev/null +++ b/include/lldb/API/SBSymbolContextList.h @@ -0,0 +1,57 @@ +//===-- SBSymbolContextList.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBSymbolContextList_h_ +#define LLDB_SBSymbolContextList_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBSymbolContext.h" + +namespace lldb { + +class LLDB_API SBSymbolContextList { +public: + SBSymbolContextList(); + + SBSymbolContextList(const lldb::SBSymbolContextList &rhs); + + ~SBSymbolContextList(); + + const lldb::SBSymbolContextList & + operator=(const lldb::SBSymbolContextList &rhs); + + bool IsValid() const; + + uint32_t GetSize() const; + + lldb::SBSymbolContext GetContextAtIndex(uint32_t idx); + + bool GetDescription(lldb::SBStream &description); + + void Append(lldb::SBSymbolContext &sc); + + void Append(lldb::SBSymbolContextList &sc_list); + + void Clear(); + +protected: + friend class SBModule; + friend class SBTarget; + + lldb_private::SymbolContextList *operator->() const; + + lldb_private::SymbolContextList &operator*() const; + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBSymbolContextList_h_ diff --git a/include/lldb/API/SBTarget.h b/include/lldb/API/SBTarget.h new file mode 100644 index 000000000..62398fcd4 --- /dev/null +++ b/include/lldb/API/SBTarget.h @@ -0,0 +1,847 @@ +//===-- 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_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBAttachInfo.h" +#include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBBroadcaster.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBFileSpecList.h" +#include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBSymbolContextList.h" +#include "lldb/API/SBType.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBWatchpoint.h" + +namespace lldb { + +class SBPlatform; + +class LLDB_API SBTarget { +public: + //------------------------------------------------------------------ + // Broadcaster bits. + //------------------------------------------------------------------ + enum { + eBroadcastBitBreakpointChanged = (1 << 0), + eBroadcastBitModulesLoaded = (1 << 1), + eBroadcastBitModulesUnloaded = (1 << 2), + eBroadcastBitWatchpointChanged = (1 << 3), + eBroadcastBitSymbolsLoaded = (1 << 4) + }; + + //------------------------------------------------------------------ + // Constructors + //------------------------------------------------------------------ + SBTarget(); + + SBTarget(const lldb::SBTarget &rhs); + + SBTarget(const lldb::TargetSP &target_sp); + + //------------------------------------------------------------------ + // Destructor + //------------------------------------------------------------------ + ~SBTarget(); + + const lldb::SBTarget &operator=(const lldb::SBTarget &rhs); + + bool IsValid() const; + + static bool EventIsTargetEvent(const lldb::SBEvent &event); + + static lldb::SBTarget GetTargetFromEvent(const lldb::SBEvent &event); + + static uint32_t GetNumModulesFromEvent(const lldb::SBEvent &event); + + static lldb::SBModule GetModuleAtIndexFromEvent(const uint32_t idx, + const lldb::SBEvent &event); + + static const char *GetBroadcasterClassName(); + + lldb::SBProcess GetProcess(); + + //------------------------------------------------------------------ + /// Return the platform object associated with the target. + /// + /// After return, the platform object should be checked for + /// validity. + /// + /// @return + /// A platform object. + //------------------------------------------------------------------ + lldb::SBPlatform GetPlatform(); + + //------------------------------------------------------------------ + /// Install any binaries that need to be installed. + /// + /// This function does nothing when debugging on the host system. + /// When connected to remote platforms, the target's main executable + /// and any modules that have their remote install path set will be + /// installed on the remote platform. If the main executable doesn't + /// have an install location set, it will be installed in the remote + /// platform's working directory. + /// + /// @return + /// An error describing anything that went wrong during + /// installation. + //------------------------------------------------------------------ + SBError Install(); + + //------------------------------------------------------------------ + /// Launch a new process. + /// + /// Launch a new process by spawning a new process using the + /// target object's executable module's file as the file to launch. + /// Arguments are given in \a argv, and the environment variables + /// are in \a envp. Standard input and output files can be + /// optionally re-directed to \a stdin_path, \a stdout_path, and + /// \a stderr_path. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] argv + /// The argument array. + /// + /// @param[in] envp + /// The environment array. + /// + /// @param[in] stdin_path + /// The path to use when re-directing the STDIN of the new + /// process. If all stdXX_path arguments are nullptr, 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 nullptr, 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 nullptr, a pseudo + /// terminal will be used. + /// + /// @param[in] working_directory + /// The working directory to have the child process run in + /// + /// @param[in] launch_flags + /// Some launch options specified by logical OR'ing + /// lldb::LaunchFlags enumeration values together. + /// + /// @param[in] stop_at_entry + /// If false do not stop the inferior at the entry point. + /// + /// @param[out] error + /// An error object. Contains the reason if there is some failure. + /// + /// @return + /// A process object for the newly created process. + //------------------------------------------------------------------ + lldb::SBProcess Launch(SBListener &listener, char const **argv, + char const **envp, const char *stdin_path, + const char *stdout_path, const char *stderr_path, + const char *working_directory, + uint32_t launch_flags, // See LaunchFlags + bool stop_at_entry, lldb::SBError &error); + + SBProcess LoadCore(const char *core_file); + + //------------------------------------------------------------------ + /// Launch a new process with sensible defaults. + /// + /// @param[in] argv + /// The argument array. + /// + /// @param[in] envp + /// The environment array. + /// + /// @param[in] working_directory + /// The working directory to have the child process run in + /// + /// Default: listener + /// Set to the target's debugger (SBTarget::GetDebugger()) + /// + /// Default: launch_flags + /// Empty launch flags + /// + /// Default: stdin_path + /// Default: stdout_path + /// Default: stderr_path + /// A pseudo terminal will be used. + /// + /// @return + /// A process object for the newly created process. + //------------------------------------------------------------------ + SBProcess LaunchSimple(const char **argv, const char **envp, + const char *working_directory); + + SBProcess Launch(SBLaunchInfo &launch_info, SBError &error); + + SBProcess Attach(SBAttachInfo &attach_info, SBError &error); + + //------------------------------------------------------------------ + /// Attach to process with pid. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] pid + /// The process ID to attach to. + /// + /// @param[out] error + /// An error explaining what went wrong if attach fails. + /// + /// @return + /// A process object for the attached process. + //------------------------------------------------------------------ + lldb::SBProcess AttachToProcessWithID(SBListener &listener, lldb::pid_t pid, + lldb::SBError &error); + +#if defined(__APPLE__) + // We need to keep this around for a build or two since Xcode links + // to the 32 bit version of this function. We will take it out soon. + lldb::SBProcess AttachToProcessWithID(SBListener &listener, + ::pid_t pid, // 32 bit int process ID + lldb::SBError &error); // DEPRECATED +#endif + + //------------------------------------------------------------------ + /// Attach to process with name. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] name + /// Basename of process to attach to. + /// + /// @param[in] wait_for + /// If true wait for a new instance of 'name' to be launched. + /// + /// @param[out] error + /// An error explaining what went wrong if attach fails. + /// + /// @return + /// A process object for the attached process. + //------------------------------------------------------------------ + lldb::SBProcess AttachToProcessWithName(SBListener &listener, + const char *name, bool wait_for, + lldb::SBError &error); + + //------------------------------------------------------------------ + /// Connect to a remote debug server with url. + /// + /// @param[in] listener + /// An optional listener that will receive all process events. + /// If \a listener is valid then \a listener will listen to all + /// process events. If not valid, then this target's debugger + /// (SBTarget::GetDebugger()) will listen to all process events. + /// + /// @param[in] url + /// The url to connect to, e.g., 'connect://localhost:12345'. + /// + /// @param[in] plugin_name + /// The plugin name to be used; can be nullptr. + /// + /// @param[out] error + /// An error explaining what went wrong if the connect fails. + /// + /// @return + /// A process object for the connected process. + //------------------------------------------------------------------ + lldb::SBProcess ConnectRemote(SBListener &listener, const char *url, + const char *plugin_name, SBError &error); + + lldb::SBFileSpec GetExecutable(); + + bool AddModule(lldb::SBModule &module); + + lldb::SBModule AddModule(const char *path, const char *triple, + const char *uuid); + + lldb::SBModule AddModule(const char *path, const char *triple, + const char *uuid_cstr, const char *symfile); + + lldb::SBModule AddModule(const SBModuleSpec &module_spec); + + uint32_t GetNumModules() const; + + lldb::SBModule GetModuleAtIndex(uint32_t idx); + + bool RemoveModule(lldb::SBModule module); + + lldb::SBDebugger GetDebugger() const; + + lldb::SBModule FindModule(const lldb::SBFileSpec &file_spec); + + lldb::ByteOrder GetByteOrder(); + + uint32_t GetAddressByteSize(); + + const char *GetTriple(); + + //------------------------------------------------------------------ + /// Architecture data byte width accessor + /// + /// @return + /// The size in 8-bit (host) bytes of a minimum addressable + /// unit from the Architecture's data bus + //------------------------------------------------------------------ + uint32_t GetDataByteSize(); + + //------------------------------------------------------------------ + /// Architecture code byte width accessor + /// + /// @return + /// The size in 8-bit (host) bytes of a minimum addressable + /// unit from the Architecture's code bus + //------------------------------------------------------------------ + uint32_t GetCodeByteSize(); + + //------------------------------------------------------------------ + /// Set the base load address for a module section. + /// + /// @param[in] section + /// The section whose base load address will be set within this + /// target. + /// + /// @param[in] section_base_addr + /// The base address for the section. + /// + /// @return + /// An error to indicate success, fail, and any reason for + /// failure. + //------------------------------------------------------------------ + lldb::SBError SetSectionLoadAddress(lldb::SBSection section, + lldb::addr_t section_base_addr); + + //------------------------------------------------------------------ + /// Clear the base load address for a module section. + /// + /// @param[in] section + /// The section whose base load address will be cleared within + /// this target. + /// + /// @return + /// An error to indicate success, fail, and any reason for + /// failure. + //------------------------------------------------------------------ + lldb::SBError ClearSectionLoadAddress(lldb::SBSection section); + + //------------------------------------------------------------------ + /// Slide all file addresses for all module sections so that \a module + /// appears to loaded at these slide addresses. + /// + /// When you need all sections within a module to be loaded at a + /// rigid slide from the addresses found in the module object file, + /// this function will allow you to easily and quickly slide all + /// module sections. + /// + /// @param[in] module + /// The module to load. + /// + /// @param[in] sections_offset + /// An offset that will be applied to all section file addresses + /// (the virtual addresses found in the object file itself). + /// + /// @return + /// An error to indicate success, fail, and any reason for + /// failure. + //------------------------------------------------------------------ + lldb::SBError SetModuleLoadAddress(lldb::SBModule module, + int64_t sections_offset); + + //------------------------------------------------------------------ + /// Clear the section base load addresses for all sections in a module. + /// + /// @param[in] module + /// The module to unload. + /// + /// @return + /// An error to indicate success, fail, and any reason for + /// failure. + //------------------------------------------------------------------ + lldb::SBError ClearModuleLoadAddress(lldb::SBModule module); + + //------------------------------------------------------------------ + /// Find functions by name. + /// + /// @param[in] name + /// The name of the function we are looking for. + /// + /// @param[in] name_type_mask + /// A logical OR of one or more FunctionNameType enum bits that + /// indicate what kind of names should be used when doing the + /// lookup. Bits include fully qualified names, base names, + /// C++ methods, or ObjC selectors. + /// See FunctionNameType for more details. + /// + /// @return + /// A lldb::SBSymbolContextList that gets filled in with all of + /// the symbol contexts for all the matches. + //------------------------------------------------------------------ + lldb::SBSymbolContextList + FindFunctions(const char *name, + uint32_t name_type_mask = lldb::eFunctionNameTypeAny); + + //------------------------------------------------------------------ + /// Find global and static variables by name. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a max_matches. + /// + /// @return + /// A list of matched variables in an SBValueList. + //------------------------------------------------------------------ + lldb::SBValueList FindGlobalVariables(const char *name, uint32_t max_matches); + + //------------------------------------------------------------------ + /// Find the first global (or static) variable by name. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @return + /// An SBValue that gets filled in with the found variable (if any). + //------------------------------------------------------------------ + lldb::SBValue FindFirstGlobalVariable(const char *name); + + //------------------------------------------------------------------ + /// Find global and static variables by pattern. + /// + /// @param[in] name + /// The pattern to search for global or static variables + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a max_matches. + /// + /// @param[in] matchtype + /// The match type to use. + /// + /// @return + /// A list of matched variables in an SBValueList. + //------------------------------------------------------------------ + lldb::SBValueList FindGlobalVariables(const char *name, uint32_t max_matches, + MatchType matchtype); + + //------------------------------------------------------------------ + /// Find global functions by their name with pattern matching. + /// + /// @param[in] name + /// The pattern to search for global or static variables + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a max_matches. + /// + /// @param[in] matchtype + /// The match type to use. + /// + /// @return + /// A list of matched variables in an SBValueList. + //------------------------------------------------------------------ + lldb::SBSymbolContextList FindGlobalFunctions(const char *name, + uint32_t max_matches, + MatchType matchtype); + + void Clear(); + + //------------------------------------------------------------------ + /// Resolve a current file address into a section offset address. + /// + /// @param[in] file_addr + /// The file address to resolve. + /// + /// @return + /// An SBAddress which will be valid if... + //------------------------------------------------------------------ + lldb::SBAddress ResolveFileAddress(lldb::addr_t file_addr); + + //------------------------------------------------------------------ + /// Resolve a current load address into a section offset address. + /// + /// @param[in] vm_addr + /// A virtual address from the current process state that is to + /// be translated into a section offset address. + /// + /// @return + /// An SBAddress which will be valid if \a vm_addr was + /// successfully resolved into a section offset address, or an + /// invalid SBAddress if \a vm_addr doesn't resolve to a section + /// in a module. + //------------------------------------------------------------------ + lldb::SBAddress ResolveLoadAddress(lldb::addr_t vm_addr); + + //------------------------------------------------------------------ + /// Resolve a current load address into a section offset address + /// using the process stop ID to identify a time in the past. + /// + /// @param[in] stop_id + /// Each time a process stops, the process stop ID integer gets + /// incremented. These stop IDs are used to identify past times + /// and can be used in history objects as a cheap way to store + /// the time at which the sample was taken. Specifying + /// UINT32_MAX will always resolve the address using the + /// currently loaded sections. + /// + /// @param[in] vm_addr + /// A virtual address from the current process state that is to + /// be translated into a section offset address. + /// + /// @return + /// An SBAddress which will be valid if \a vm_addr was + /// successfully resolved into a section offset address, or an + /// invalid SBAddress if \a vm_addr doesn't resolve to a section + /// in a module. + //------------------------------------------------------------------ + lldb::SBAddress ResolvePastLoadAddress(uint32_t stop_id, + lldb::addr_t vm_addr); + + SBSymbolContext ResolveSymbolContextForAddress(const SBAddress &addr, + uint32_t resolve_scope); + + //------------------------------------------------------------------ + /// Read target memory. If a target process is running then memory + /// is read from here. Otherwise the memory is read from the object + /// files. For a target whose bytes are sized as a multiple of host + /// bytes, the data read back will preserve the target's byte order. + /// + /// @param[in] addr + /// A target address to read from. + /// + /// @param[out] buf + /// The buffer to read memory into. + /// + /// @param[in] size + /// The maximum number of host bytes to read in the buffer passed + /// into this call + /// + /// @param[out] error + /// Status information is written here if the memory read fails. + /// + /// @return + /// The amount of data read in host bytes. + //------------------------------------------------------------------ + size_t ReadMemory(const SBAddress addr, void *buf, size_t size, + lldb::SBError &error); + + lldb::SBBreakpoint BreakpointCreateByLocation(const char *file, + uint32_t line); + + lldb::SBBreakpoint + BreakpointCreateByLocation(const lldb::SBFileSpec &file_spec, uint32_t line); + + lldb::SBBreakpoint + BreakpointCreateByLocation(const lldb::SBFileSpec &file_spec, uint32_t line, + lldb::addr_t offset); + + lldb::SBBreakpoint + BreakpointCreateByLocation(const lldb::SBFileSpec &file_spec, uint32_t line, + lldb::addr_t offset, SBFileSpecList &module_list); + + lldb::SBBreakpoint BreakpointCreateByName(const char *symbol_name, + const char *module_name = nullptr); + + // This version uses name_type_mask = eFunctionNameTypeAuto + lldb::SBBreakpoint + BreakpointCreateByName(const char *symbol_name, + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByName( + const char *symbol_name, + uint32_t + name_type_mask, // Logical OR one or more FunctionNameType enum bits + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByName( + const char *symbol_name, + uint32_t + name_type_mask, // Logical OR one or more FunctionNameType enum bits + lldb::LanguageType symbol_language, + const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByNames( + const char *symbol_name[], uint32_t num_names, + uint32_t + name_type_mask, // Logical OR one or more FunctionNameType enum bits + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByNames( + const char *symbol_name[], uint32_t num_names, + uint32_t + name_type_mask, // Logical OR one or more FunctionNameType enum bits + lldb::LanguageType symbol_language, + const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByNames( + const char *symbol_name[], uint32_t num_names, + uint32_t + name_type_mask, // Logical OR one or more FunctionNameType enum bits + lldb::LanguageType symbol_language, + lldb::addr_t offset, const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByRegex(const char *symbol_name_regex, + const char *module_name = nullptr); + + lldb::SBBreakpoint + BreakpointCreateByRegex(const char *symbol_name_regex, + const SBFileSpecList &module_list, + const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint BreakpointCreateByRegex( + const char *symbol_name_regex, lldb::LanguageType symbol_language, + const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list); + + lldb::SBBreakpoint + BreakpointCreateBySourceRegex(const char *source_regex, + const SBFileSpec &source_file, + const char *module_name = nullptr); + + lldb::SBBreakpoint + BreakpointCreateBySourceRegex(const char *source_regex, + const SBFileSpecList &module_list, + const SBFileSpecList &source_file); + + lldb::SBBreakpoint BreakpointCreateBySourceRegex( + const char *source_regex, const SBFileSpecList &module_list, + const SBFileSpecList &source_file, const SBStringList &func_names); + + lldb::SBBreakpoint BreakpointCreateForException(lldb::LanguageType language, + bool catch_bp, bool throw_bp); + + lldb::SBBreakpoint BreakpointCreateByAddress(addr_t address); + + lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); + + //------------------------------------------------------------------ + /// Read breakpoints from source_file and return the newly created + /// breakpoints in bkpt_list. + /// + /// @param[in] source_file + /// The file from which to read the breakpoints. + /// + /// @param[out] new_bps + /// A list of the newly created breakpoints. + /// + /// @return + /// An SBError detailing any errors in reading in the breakpoints. + //------------------------------------------------------------------ + lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, + SBBreakpointList &new_bps); + + //------------------------------------------------------------------ + /// Read breakpoints from source_file and return the newly created + /// breakpoints in bkpt_list. + /// + /// @param[in] source_file + /// The file from which to read the breakpoints. + /// + /// @param[in] matching_names + /// Only read in breakpoints whose names match one of the names in this + /// list. + /// + /// @param[out] new_bps + /// A list of the newly created breakpoints. + /// + /// @return + /// An SBError detailing any errors in reading in the breakpoints. + //------------------------------------------------------------------ + lldb::SBError BreakpointsCreateFromFile(SBFileSpec &source_file, + SBStringList &matching_names, + SBBreakpointList &new_bps); + + //------------------------------------------------------------------ + /// Write breakpoints to dest_file. + /// + /// @param[in] dest_file + /// The file to which to write the breakpoints. + /// + /// @return + /// An SBError detailing any errors in writing in the breakpoints. + //------------------------------------------------------------------ + lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file); + + //------------------------------------------------------------------ + /// Write breakpoints listed in bkpt_list to dest_file. + /// + /// @param[in] dest_file + /// The file to which to write the breakpoints. + /// + /// @param[in] bkpt_list + /// Only write breakpoints from this list. + /// + /// @param[in] append + /// If \btrue, append the breakpoints in bkpt_list to the others + /// serialized in dest_file. If dest_file doesn't exist, then a new + /// file will be created and the breakpoints in bkpt_list written to it. + /// + /// @return + /// An SBError detailing any errors in writing in the breakpoints. + //------------------------------------------------------------------ + lldb::SBError BreakpointsWriteToFile(SBFileSpec &dest_file, + SBBreakpointList &bkpt_list, + bool append = false); + + uint32_t GetNumBreakpoints() const; + + lldb::SBBreakpoint GetBreakpointAtIndex(uint32_t idx) const; + + bool BreakpointDelete(break_id_t break_id); + + lldb::SBBreakpoint FindBreakpointByID(break_id_t break_id); + + // Finds all breakpoints by name, returning the list in bkpt_list. Returns + // false if the name is not a valid breakpoint name, true otherwise. + bool FindBreakpointsByName(const char *name, SBBreakpointList &bkpt_list); + + bool EnableAllBreakpoints(); + + bool DisableAllBreakpoints(); + + bool DeleteAllBreakpoints(); + + uint32_t GetNumWatchpoints() const; + + lldb::SBWatchpoint GetWatchpointAtIndex(uint32_t idx) const; + + bool DeleteWatchpoint(lldb::watch_id_t watch_id); + + lldb::SBWatchpoint FindWatchpointByID(lldb::watch_id_t watch_id); + + lldb::SBWatchpoint WatchAddress(lldb::addr_t addr, size_t size, bool read, + bool write, SBError &error); + + bool EnableAllWatchpoints(); + + bool DisableAllWatchpoints(); + + bool DeleteAllWatchpoints(); + + lldb::SBBroadcaster GetBroadcaster() const; + + lldb::SBType FindFirstType(const char *type); + + lldb::SBTypeList FindTypes(const char *type); + + lldb::SBType GetBasicType(lldb::BasicType type); + + lldb::SBValue CreateValueFromAddress(const char *name, lldb::SBAddress addr, + lldb::SBType type); + + lldb::SBValue CreateValueFromData(const char *name, lldb::SBData data, + lldb::SBType type); + + lldb::SBValue CreateValueFromExpression(const char *name, const char *expr); + + SBSourceManager GetSourceManager(); + + lldb::SBInstructionList ReadInstructions(lldb::SBAddress base_addr, + uint32_t count); + + lldb::SBInstructionList ReadInstructions(lldb::SBAddress base_addr, + uint32_t count, + const char *flavor_string); + + lldb::SBInstructionList GetInstructions(lldb::SBAddress base_addr, + const void *buf, size_t size); + + // The "WithFlavor" is necessary to keep SWIG from getting confused about + // overloaded arguments when + // using the buf + size -> Python Object magic. + + lldb::SBInstructionList GetInstructionsWithFlavor(lldb::SBAddress base_addr, + const char *flavor_string, + const void *buf, + size_t size); + + lldb::SBInstructionList GetInstructions(lldb::addr_t base_addr, + const void *buf, size_t size); + + lldb::SBInstructionList GetInstructionsWithFlavor(lldb::addr_t base_addr, + const char *flavor_string, + const void *buf, + size_t size); + + lldb::SBSymbolContextList FindSymbols(const char *name, + lldb::SymbolType type = eSymbolTypeAny); + + bool operator==(const lldb::SBTarget &rhs) const; + + bool operator!=(const lldb::SBTarget &rhs) const; + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBValue EvaluateExpression(const char *expr); + + lldb::SBValue EvaluateExpression(const char *expr, + const SBExpressionOptions &options); + + lldb::addr_t GetStackRedZoneSize(); + + lldb::SBLaunchInfo GetLaunchInfo() const; + + void SetLaunchInfo(const lldb::SBLaunchInfo &launch_info); + +protected: + friend class SBAddress; + friend class SBBlock; + friend class SBBreakpointList; + friend class SBDebugger; + friend class SBExecutionContext; + friend class SBFunction; + friend class SBInstruction; + friend class SBModule; + friend class SBProcess; + friend class SBSection; + friend class SBSourceManager; + friend class SBSymbol; + friend class SBValue; + + //------------------------------------------------------------------ + // Constructors are private, use static Target::Create function to + // create an instance of this class. + //------------------------------------------------------------------ + + lldb::TargetSP GetSP() const; + + void SetSP(const lldb::TargetSP &target_sp); + +private: + lldb::TargetSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBTarget_h_ diff --git a/include/lldb/API/SBThread.h b/include/lldb/API/SBThread.h new file mode 100644 index 000000000..502e5c973 --- /dev/null +++ b/include/lldb/API/SBThread.h @@ -0,0 +1,220 @@ +//===-- SBThread.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBThread_h_ +#define LLDB_SBThread_h_ + +#include "lldb/API/SBDefines.h" + +#include + +namespace lldb { + +class SBFrame; + +class LLDB_API SBThread { +public: + enum { + eBroadcastBitStackChanged = (1 << 0), + eBroadcastBitThreadSuspended = (1 << 1), + eBroadcastBitThreadResumed = (1 << 2), + eBroadcastBitSelectedFrameChanged = (1 << 3), + eBroadcastBitThreadSelected = (1 << 4) + }; + + static const char *GetBroadcasterClassName(); + + SBThread(); + + SBThread(const lldb::SBThread &thread); + + SBThread(const lldb::ThreadSP &lldb_object_sp); + + ~SBThread(); + + lldb::SBQueue GetQueue() const; + + bool IsValid() const; + + void Clear(); + + lldb::StopReason GetStopReason(); + + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + size_t GetStopReasonDataCount(); + + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + uint64_t GetStopReasonDataAtIndex(uint32_t idx); + + bool GetStopReasonExtendedInfoAsJSON(lldb::SBStream &stream); + + SBThreadCollection + GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type); + + size_t GetStopDescription(char *dst, size_t dst_len); + + SBValue GetStopReturnValue(); + + lldb::tid_t GetThreadID() const; + + uint32_t GetIndexID() const; + + const char *GetName() const; + + const char *GetQueueName() const; + + lldb::queue_id_t GetQueueID() const; + + bool GetInfoItemByPathAsString(const char *path, SBStream &strm); + + void StepOver(lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void StepInto(lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void StepInto(const char *target_name, + lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void StepInto(const char *target_name, uint32_t end_line, SBError &error, + lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping); + + void StepOut(); + + void StepOutOfFrame(lldb::SBFrame &frame); + + void StepInstruction(bool step_over); + + SBError StepOverUntil(lldb::SBFrame &frame, lldb::SBFileSpec &file_spec, + uint32_t line); + + SBError StepUsingScriptedThreadPlan(const char *script_class_name); + + SBError StepUsingScriptedThreadPlan(const char *script_class_name, + bool resume_immediately); + + SBError JumpToLine(lldb::SBFileSpec &file_spec, uint32_t line); + + void RunToAddress(lldb::addr_t addr); + + SBError ReturnFromFrame(SBFrame &frame, SBValue &return_value); + + SBError UnwindInnermostExpression(); + + //-------------------------------------------------------------------------- + /// LLDB currently supports process centric debugging which means when any + /// thread in a process stops, all other threads are stopped. The Suspend() + /// call here tells our process to suspend a thread and not let it run when + /// the other threads in a process are allowed to run. So when + /// SBProcess::Continue() is called, any threads that aren't suspended will + /// be allowed to run. If any of the SBThread functions for stepping are + /// called (StepOver, StepInto, StepOut, StepInstruction, RunToAddress), the + /// thread will not be allowed to run and these functions will simply return. + /// + /// Eventually we plan to add support for thread centric debugging where + /// each thread is controlled individually and each thread would broadcast + /// its state, but we haven't implemented this yet. + /// + /// Likewise the SBThread::Resume() call will again allow the thread to run + /// when the process is continued. + /// + /// Suspend() and Resume() functions are not currently reference counted, if + /// anyone has the need for them to be reference counted, please let us + /// know. + //-------------------------------------------------------------------------- + bool Suspend(); + + bool Resume(); + + bool IsSuspended(); + + bool IsStopped(); + + uint32_t GetNumFrames(); + + lldb::SBFrame GetFrameAtIndex(uint32_t idx); + + lldb::SBFrame GetSelectedFrame(); + + lldb::SBFrame SetSelectedFrame(uint32_t frame_idx); + + static bool EventIsThreadEvent(const SBEvent &event); + + static SBFrame GetStackFrameFromEvent(const SBEvent &event); + + static SBThread GetThreadFromEvent(const SBEvent &event); + + lldb::SBProcess GetProcess(); + + const lldb::SBThread &operator=(const lldb::SBThread &rhs); + + bool operator==(const lldb::SBThread &rhs) const; + + bool operator!=(const lldb::SBThread &rhs) const; + + bool GetDescription(lldb::SBStream &description) const; + + bool GetDescription(lldb::SBStream &description, bool stop_format) const; + + bool GetStatus(lldb::SBStream &status) const; + + SBThread GetExtendedBacktraceThread(const char *type); + + uint32_t GetExtendedBacktraceOriginatingIndexID(); + + bool SafeToCallFunctions(); + +#ifndef SWIG + lldb_private::Thread *operator->(); + + lldb_private::Thread *get(); + +#endif + +protected: + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBExecutionContext; + friend class SBFrame; + friend class SBProcess; + friend class SBDebugger; + friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; + + void SetThread(const lldb::ThreadSP &lldb_object_sp); + +#ifndef SWIG + SBError ResumeNewPlan(lldb_private::ExecutionContext &exe_ctx, + lldb_private::ThreadPlan *new_plan); +#endif + +private: + lldb::ExecutionContextRefSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThread_h_ diff --git a/include/lldb/API/SBThreadCollection.h b/include/lldb/API/SBThreadCollection.h new file mode 100644 index 000000000..715b0826b --- /dev/null +++ b/include/lldb/API/SBThreadCollection.h @@ -0,0 +1,56 @@ +//===-- SBThreadCollection.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_SBThreadCollection_h_ +#define LLDB_SBThreadCollection_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBThreadCollection { +public: + SBThreadCollection(); + + SBThreadCollection(const SBThreadCollection &rhs); + + const SBThreadCollection &operator=(const SBThreadCollection &rhs); + + ~SBThreadCollection(); + + bool IsValid() const; + + size_t GetSize(); + + lldb::SBThread GetThreadAtIndex(size_t idx); + +protected: + // Mimic shared pointer... + lldb_private::ThreadCollection *get() const; + + lldb_private::ThreadCollection *operator->() const; + + lldb::ThreadCollectionSP &operator*(); + + const lldb::ThreadCollectionSP &operator*() const; + + SBThreadCollection(const lldb::ThreadCollectionSP &threads); + + void SetOpaque(const lldb::ThreadCollectionSP &threads); + +private: + friend class SBProcess; + friend class SBThread; + + lldb::ThreadCollectionSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThreadCollection_h_ diff --git a/include/lldb/API/SBThreadPlan.h b/include/lldb/API/SBThreadPlan.h new file mode 100644 index 000000000..abc14bf8f --- /dev/null +++ b/include/lldb/API/SBThreadPlan.h @@ -0,0 +1,115 @@ +//===-- 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_SBThreadPlan_h_ +#define LLDB_SBThreadPlan_h_ + +#include "lldb/API/SBDefines.h" + +#include + +namespace lldb { + +class LLDB_API SBThreadPlan { + + friend class lldb_private::ThreadPlan; + +public: + SBThreadPlan(); + + SBThreadPlan(const lldb::SBThreadPlan &threadPlan); + + SBThreadPlan(const lldb::ThreadPlanSP &lldb_object_sp); + + SBThreadPlan(lldb::SBThread &thread, const char *class_name); + + ~SBThreadPlan(); + + bool IsValid() const; + + void Clear(); + + lldb::StopReason GetStopReason(); + + /// Get the number of words associated with the stop reason. + /// See also GetStopReasonDataAtIndex(). + size_t GetStopReasonDataCount(); + + //-------------------------------------------------------------------------- + /// Get information associated with a stop reason. + /// + /// Breakpoint stop reasons will have data that consists of pairs of + /// breakpoint IDs followed by the breakpoint location IDs (they always come + /// in pairs). + /// + /// Stop Reason Count Data Type + /// ======================== ===== ========================================= + /// eStopReasonNone 0 + /// eStopReasonTrace 0 + /// eStopReasonBreakpoint N duple: {breakpoint id, location id} + /// eStopReasonWatchpoint 1 watchpoint id + /// eStopReasonSignal 1 unix signal number + /// eStopReasonException N exception data + /// eStopReasonExec 0 + /// eStopReasonPlanComplete 0 + //-------------------------------------------------------------------------- + uint64_t GetStopReasonDataAtIndex(uint32_t idx); + + SBThread GetThread() const; + + const lldb::SBThreadPlan &operator=(const lldb::SBThreadPlan &rhs); + + bool GetDescription(lldb::SBStream &description) const; + + void SetPlanComplete(bool success); + + bool IsPlanComplete(); + + bool IsPlanStale(); + + bool IsValid(); + + // This section allows an SBThreadPlan to push another of the common types of + // plans... + SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan QueueThreadPlanForStepInRange(SBAddress &start_address, + lldb::addr_t range_size); + + SBThreadPlan QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, + bool first_insn = false); + + SBThreadPlan QueueThreadPlanForRunToAddress(SBAddress address); + +#ifndef SWIG + lldb_private::ThreadPlan *get(); +#endif + +protected: + friend class SBBreakpoint; + friend class SBBreakpointLocation; + friend class SBFrame; + friend class SBProcess; + friend class SBDebugger; + friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; + +#ifndef SWIG + void SetThreadPlan(const lldb::ThreadPlanSP &lldb_object_sp); +#endif + +private: + lldb::ThreadPlanSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBThreadPlan_h_ diff --git a/include/lldb/API/SBTrace.h b/include/lldb/API/SBTrace.h new file mode 100644 index 000000000..244a01e5c --- /dev/null +++ b/include/lldb/API/SBTrace.h @@ -0,0 +1,123 @@ +//===-- SBTrace.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_SBTrace_h_ +#define LLDB_SBTrace_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBError.h" + +class TraceImpl; + +namespace lldb { + +class LLDB_API SBTrace { +public: + SBTrace(); + //------------------------------------------------------------------ + /// Obtain the trace data as raw bytes. + /// + /// @param[out] error + /// An error explaining what went wrong. + /// + /// @param[in] buf + /// Buffer to write the trace data to. + /// + /// @param[in] size + /// The size of the buffer used to read the data. This is + /// also the size of the data intended to read. It is also + /// possible to partially read the trace data for some trace + /// technologies by specifying a smaller buffer. + /// + /// @param[in] offset + /// The start offset to begin reading the trace data. + /// + /// @param[in] thread_id + /// Tracing could be started for the complete process or a + /// single thread, in the first case the traceid obtained would + /// map to all the threads existing within the process and the + /// ones spawning later. The thread_id parameter can be used in + /// such a scenario to select the trace data for a specific + /// thread. + /// + /// @return + /// The size of the trace data effectively read by the API call. + //------------------------------------------------------------------ + size_t GetTraceData(SBError &error, void *buf, size_t size, size_t offset = 0, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + + //------------------------------------------------------------------ + /// Obtain any meta data as raw bytes for the tracing instance. + /// The input parameter definition is similar to the previous + /// function. + //------------------------------------------------------------------ + size_t GetMetaData(SBError &error, void *buf, size_t size, size_t offset = 0, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + + //------------------------------------------------------------------ + /// Stop the tracing instance. Stopping the trace will also + /// lead to deletion of any gathered trace data. + /// + /// @param[out] error + /// An error explaining what went wrong. + /// + /// @param[in] thread_id + /// The trace id could map to a tracing instance for a thread + /// or could also map to a group of threads being traced with + /// the same trace options. A thread_id is normally optional + /// except in the case of tracing a complete process and tracing + /// needs to switched off on a particular thread. + /// A situation could occur where initially a thread (lets say + /// thread A) is being individually traced with a particular + /// trace id and then tracing is started on the complete + /// process, in this case thread A will continue without any + /// change. All newly spawned threads would be traced with the + /// trace id of the process. + /// Now if the StopTrace API is called for the whole process, + /// thread A will not be stopped and must be stopped separately. + //------------------------------------------------------------------ + void StopTrace(SBError &error, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + + //------------------------------------------------------------------ + /// Get the trace configuration being used for the trace instance. + /// The threadid in the SBTraceOptions needs to be set when the + /// configuration used by a specific thread is being requested. + /// + /// @param[out] options + /// The trace options actually used by the trace instance + /// would be filled by the API. + /// + /// @param[out] error + /// An error explaining what went wrong. + //------------------------------------------------------------------ + void GetTraceConfig(SBTraceOptions &options, SBError &error); + + lldb::user_id_t GetTraceUID(); + + bool IsValid(); + +protected: + typedef std::shared_ptr TraceImplSP; + + friend class SBProcess; + + void SetTraceUID(lldb::user_id_t uid); + + TraceImplSP m_trace_impl_sp; + + lldb::ProcessSP GetSP() const; + + void SetSP(const ProcessSP &process_sp); + + lldb::ProcessWP m_opaque_wp; +}; +} // namespace lldb + +#endif // LLDB_SBTrace_h_ diff --git a/include/lldb/API/SBTraceOptions.h b/include/lldb/API/SBTraceOptions.h new file mode 100644 index 000000000..c9735e1ca --- /dev/null +++ b/include/lldb/API/SBTraceOptions.h @@ -0,0 +1,58 @@ +//===-- SBTraceOptions ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SBTRACEOPTIONS_H_ +#define SBTRACEOPTIONS_H_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBTraceOptions { +public: + SBTraceOptions(); + + lldb::TraceType getType() const; + + uint64_t getTraceBufferSize() const; + + /// The trace parameters consist of any custom parameters + /// apart from the generic parameters such as + /// TraceType, trace_buffer_size and meta_data_buffer_size. + /// The returned parameters would be formatted as a JSON Dictionary. + lldb::SBStructuredData getTraceParams(lldb::SBError &error); + + uint64_t getMetaDataBufferSize() const; + + /// SBStructuredData is meant to hold any custom parameters + /// apart from meta buffer size and trace size. They should + /// be formatted as a JSON Dictionary. + void setTraceParams(lldb::SBStructuredData ¶ms); + + void setType(lldb::TraceType type); + + void setTraceBufferSize(uint64_t size); + + void setMetaDataBufferSize(uint64_t size); + + void setThreadID(lldb::tid_t thread_id); + + lldb::tid_t getThreadID(); + + bool IsValid(); + +protected: + friend class SBProcess; + friend class SBTrace; + + lldb::TraceOptionsSP m_traceoptions_sp; +}; +} + +#endif /* SBTRACEOPTIONS_H_ */ diff --git a/include/lldb/API/SBType.h b/include/lldb/API/SBType.h new file mode 100644 index 000000000..0dde02579 --- /dev/null +++ b/include/lldb/API/SBType.h @@ -0,0 +1,255 @@ +//===-- SBType.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBType_h_ +#define LLDB_SBType_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class SBTypeList; + +class LLDB_API SBTypeMember { +public: + SBTypeMember(); + + SBTypeMember(const lldb::SBTypeMember &rhs); + + ~SBTypeMember(); + + lldb::SBTypeMember &operator=(const lldb::SBTypeMember &rhs); + + bool IsValid() const; + + const char *GetName(); + + lldb::SBType GetType(); + + uint64_t GetOffsetInBytes(); + + uint64_t GetOffsetInBits(); + + bool IsBitfield(); + + uint32_t GetBitfieldSizeInBits(); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + +protected: + friend class SBType; + + void reset(lldb_private::TypeMemberImpl *); + + lldb_private::TypeMemberImpl &ref(); + + const lldb_private::TypeMemberImpl &ref() const; + + std::unique_ptr m_opaque_ap; +}; + +class SBTypeMemberFunction { +public: + SBTypeMemberFunction(); + + SBTypeMemberFunction(const lldb::SBTypeMemberFunction &rhs); + + ~SBTypeMemberFunction(); + + lldb::SBTypeMemberFunction &operator=(const lldb::SBTypeMemberFunction &rhs); + + bool IsValid() const; + + const char *GetName(); + + const char *GetDemangledName(); + + const char *GetMangledName(); + + lldb::SBType GetType(); + + lldb::SBType GetReturnType(); + + uint32_t GetNumberOfArguments(); + + lldb::SBType GetArgumentTypeAtIndex(uint32_t); + + lldb::MemberFunctionKind GetKind(); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + +protected: + friend class SBType; + + void reset(lldb_private::TypeMemberFunctionImpl *); + + lldb_private::TypeMemberFunctionImpl &ref(); + + const lldb_private::TypeMemberFunctionImpl &ref() const; + + lldb::TypeMemberFunctionImplSP m_opaque_sp; +}; + +class SBType { +public: + SBType(); + + SBType(const lldb::SBType &rhs); + + ~SBType(); + + bool IsValid() const; + + uint64_t GetByteSize(); + + bool IsPointerType(); + + bool IsReferenceType(); + + bool IsFunctionType(); + + bool IsPolymorphicClass(); + + bool IsArrayType(); + + bool IsVectorType(); + + bool IsTypedefType(); + + bool IsAnonymousType(); + + lldb::SBType GetPointerType(); + + lldb::SBType GetPointeeType(); + + lldb::SBType GetReferenceType(); + + lldb::SBType GetTypedefedType(); + + lldb::SBType GetDereferencedType(); + + lldb::SBType GetUnqualifiedType(); + + lldb::SBType GetArrayElementType(); + + lldb::SBType GetArrayType(uint64_t size); + + lldb::SBType GetVectorElementType(); + + lldb::SBType GetCanonicalType(); + // Get the "lldb::BasicType" enumeration for a type. If a type is not a basic + // type eBasicTypeInvalid will be returned + lldb::BasicType GetBasicType(); + + // The call below confusing and should really be renamed to "CreateBasicType" + lldb::SBType GetBasicType(lldb::BasicType type); + + uint32_t GetNumberOfFields(); + + uint32_t GetNumberOfDirectBaseClasses(); + + uint32_t GetNumberOfVirtualBaseClasses(); + + lldb::SBTypeMember GetFieldAtIndex(uint32_t idx); + + lldb::SBTypeMember GetDirectBaseClassAtIndex(uint32_t idx); + + lldb::SBTypeMember GetVirtualBaseClassAtIndex(uint32_t idx); + + lldb::SBTypeEnumMemberList GetEnumMembers(); + + uint32_t GetNumberOfTemplateArguments(); + + lldb::SBType GetTemplateArgumentType(uint32_t idx); + + lldb::TemplateArgumentKind GetTemplateArgumentKind(uint32_t idx); + + lldb::SBType GetFunctionReturnType(); + + lldb::SBTypeList GetFunctionArgumentTypes(); + + uint32_t GetNumberOfMemberFunctions(); + + lldb::SBTypeMemberFunction GetMemberFunctionAtIndex(uint32_t idx); + + const char *GetName(); + + const char *GetDisplayTypeName(); + + lldb::TypeClass GetTypeClass(); + + bool IsTypeComplete(); + + uint32_t GetTypeFlags(); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBType &operator=(const lldb::SBType &rhs); + + bool operator==(lldb::SBType &rhs); + + bool operator!=(lldb::SBType &rhs); + +protected: + lldb_private::TypeImpl &ref(); + + const lldb_private::TypeImpl &ref() const; + + lldb::TypeImplSP GetSP(); + + void SetSP(const lldb::TypeImplSP &type_impl_sp); + + lldb::TypeImplSP m_opaque_sp; + + friend class SBFunction; + friend class SBModule; + friend class SBTarget; + friend class SBTypeEnumMember; + friend class SBTypeEnumMemberList; + friend class SBTypeNameSpecifier; + friend class SBTypeMember; + friend class SBTypeMemberFunction; + friend class SBTypeList; + friend class SBValue; + + SBType(const lldb_private::CompilerType &); + SBType(const lldb::TypeSP &); + SBType(const lldb::TypeImplSP &); +}; + +class SBTypeList { +public: + SBTypeList(); + + SBTypeList(const lldb::SBTypeList &rhs); + + ~SBTypeList(); + + lldb::SBTypeList &operator=(const lldb::SBTypeList &rhs); + + bool IsValid(); + + void Append(lldb::SBType type); + + lldb::SBType GetTypeAtIndex(uint32_t index); + + uint32_t GetSize(); + +private: + std::unique_ptr m_opaque_ap; + friend class SBModule; + friend class SBCompileUnit; +}; + +} // namespace lldb + +#endif // LLDB_SBType_h_ diff --git a/include/lldb/API/SBTypeCategory.h b/include/lldb/API/SBTypeCategory.h new file mode 100644 index 000000000..f44dfc451 --- /dev/null +++ b/include/lldb/API/SBTypeCategory.h @@ -0,0 +1,133 @@ +//===-- SBTypeCategory.h --------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBTypeCategory_h_ +#define LLDB_SBTypeCategory_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBTypeCategory { +public: + SBTypeCategory(); + + SBTypeCategory(const lldb::SBTypeCategory &rhs); + + ~SBTypeCategory(); + + bool IsValid() const; + + bool GetEnabled(); + + void SetEnabled(bool); + + const char *GetName(); + + lldb::LanguageType GetLanguageAtIndex(uint32_t idx); + + uint32_t GetNumLanguages(); + + void AddLanguage(lldb::LanguageType language); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + uint32_t GetNumFormats(); + + uint32_t GetNumSummaries(); + + uint32_t GetNumFilters(); + +#ifndef LLDB_DISABLE_PYTHON + uint32_t GetNumSynthetics(); +#endif + + SBTypeNameSpecifier GetTypeNameSpecifierForFilterAtIndex(uint32_t); + + SBTypeNameSpecifier GetTypeNameSpecifierForFormatAtIndex(uint32_t); + + SBTypeNameSpecifier GetTypeNameSpecifierForSummaryAtIndex(uint32_t); + +#ifndef LLDB_DISABLE_PYTHON + SBTypeNameSpecifier GetTypeNameSpecifierForSyntheticAtIndex(uint32_t); +#endif + + SBTypeFilter GetFilterForType(SBTypeNameSpecifier); + + SBTypeFormat GetFormatForType(SBTypeNameSpecifier); + +#ifndef LLDB_DISABLE_PYTHON + SBTypeSummary GetSummaryForType(SBTypeNameSpecifier); +#endif + +#ifndef LLDB_DISABLE_PYTHON + SBTypeSynthetic GetSyntheticForType(SBTypeNameSpecifier); +#endif + +#ifndef LLDB_DISABLE_PYTHON + SBTypeFilter GetFilterAtIndex(uint32_t); +#endif + + SBTypeFormat GetFormatAtIndex(uint32_t); + +#ifndef LLDB_DISABLE_PYTHON + SBTypeSummary GetSummaryAtIndex(uint32_t); +#endif + +#ifndef LLDB_DISABLE_PYTHON + SBTypeSynthetic GetSyntheticAtIndex(uint32_t); +#endif + + bool AddTypeFormat(SBTypeNameSpecifier, SBTypeFormat); + + bool DeleteTypeFormat(SBTypeNameSpecifier); + +#ifndef LLDB_DISABLE_PYTHON + bool AddTypeSummary(SBTypeNameSpecifier, SBTypeSummary); +#endif + + bool DeleteTypeSummary(SBTypeNameSpecifier); + + bool AddTypeFilter(SBTypeNameSpecifier, SBTypeFilter); + + bool DeleteTypeFilter(SBTypeNameSpecifier); + +#ifndef LLDB_DISABLE_PYTHON + bool AddTypeSynthetic(SBTypeNameSpecifier, SBTypeSynthetic); + + bool DeleteTypeSynthetic(SBTypeNameSpecifier); +#endif + + lldb::SBTypeCategory &operator=(const lldb::SBTypeCategory &rhs); + + bool operator==(lldb::SBTypeCategory &rhs); + + bool operator!=(lldb::SBTypeCategory &rhs); + +protected: + friend class SBDebugger; + + lldb::TypeCategoryImplSP GetSP(); + + void SetSP(const lldb::TypeCategoryImplSP &typecategory_impl_sp); + + TypeCategoryImplSP m_opaque_sp; + + SBTypeCategory(const lldb::TypeCategoryImplSP &); + + SBTypeCategory(const char *); + + bool IsDefaultCategory(); +}; + +} // namespace lldb + +#endif // LLDB_SBTypeCategory_h_ diff --git a/include/lldb/API/SBTypeEnumMember.h b/include/lldb/API/SBTypeEnumMember.h new file mode 100644 index 000000000..f45c234d2 --- /dev/null +++ b/include/lldb/API/SBTypeEnumMember.h @@ -0,0 +1,80 @@ + +//===-- SBTypeEnumMember.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_SBTypeEnumMember_h_ +#define LLDB_SBTypeEnumMember_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBTypeEnumMember { +public: + SBTypeEnumMember(); + + SBTypeEnumMember(const SBTypeEnumMember &rhs); + + ~SBTypeEnumMember(); + + SBTypeEnumMember &operator=(const SBTypeEnumMember &rhs); + + bool IsValid() const; + + int64_t GetValueAsSigned(); + + uint64_t GetValueAsUnsigned(); + + const char *GetName(); + + lldb::SBType GetType(); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + +protected: + friend class SBType; + friend class SBTypeEnumMemberList; + + void reset(lldb_private::TypeEnumMemberImpl *); + + lldb_private::TypeEnumMemberImpl &ref(); + + const lldb_private::TypeEnumMemberImpl &ref() const; + + lldb::TypeEnumMemberImplSP m_opaque_sp; + + SBTypeEnumMember(const lldb::TypeEnumMemberImplSP &); +}; + +class SBTypeEnumMemberList { +public: + SBTypeEnumMemberList(); + + SBTypeEnumMemberList(const SBTypeEnumMemberList &rhs); + + ~SBTypeEnumMemberList(); + + SBTypeEnumMemberList &operator=(const SBTypeEnumMemberList &rhs); + + bool IsValid(); + + void Append(SBTypeEnumMember entry); + + SBTypeEnumMember GetTypeEnumMemberAtIndex(uint32_t index); + + uint32_t GetSize(); + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBTypeEnumMember_h_ diff --git a/include/lldb/API/SBTypeFilter.h b/include/lldb/API/SBTypeFilter.h new file mode 100644 index 000000000..19888ba7c --- /dev/null +++ b/include/lldb/API/SBTypeFilter.h @@ -0,0 +1,73 @@ +//===-- SBTypeFilter.h --------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBTypeFilter_h_ +#define LLDB_SBTypeFilter_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBTypeFilter { +public: + SBTypeFilter(); + + SBTypeFilter(uint32_t options); // see lldb::eTypeOption values + + SBTypeFilter(const lldb::SBTypeFilter &rhs); + + ~SBTypeFilter(); + + bool IsValid() const; + + uint32_t GetNumberOfExpressionPaths(); + + const char *GetExpressionPathAtIndex(uint32_t i); + + bool ReplaceExpressionPathAtIndex(uint32_t i, const char *item); + + void AppendExpressionPath(const char *item); + + void Clear(); + + uint32_t GetOptions(); + + void SetOptions(uint32_t); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBTypeFilter &operator=(const lldb::SBTypeFilter &rhs); + + bool IsEqualTo(lldb::SBTypeFilter &rhs); + + bool operator==(lldb::SBTypeFilter &rhs); + + bool operator!=(lldb::SBTypeFilter &rhs); + +protected: + friend class SBDebugger; + friend class SBTypeCategory; + friend class SBValue; + + lldb::TypeFilterImplSP GetSP(); + + void SetSP(const lldb::TypeFilterImplSP &typefilter_impl_sp); + + lldb::TypeFilterImplSP m_opaque_sp; + + SBTypeFilter(const lldb::TypeFilterImplSP &); + + bool CopyOnWrite_Impl(); +}; + +} // namespace lldb + +#endif // LLDB_SBTypeFilter_h_ diff --git a/include/lldb/API/SBTypeFormat.h b/include/lldb/API/SBTypeFormat.h new file mode 100644 index 000000000..d0429e97f --- /dev/null +++ b/include/lldb/API/SBTypeFormat.h @@ -0,0 +1,77 @@ +//===-- SBTypeFormat.h --------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBTypeFormat_h_ +#define LLDB_SBTypeFormat_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBTypeFormat { +public: + SBTypeFormat(); + + SBTypeFormat(lldb::Format format, + uint32_t options = 0); // see lldb::eTypeOption values + + SBTypeFormat(const char *type, + uint32_t options = 0); // see lldb::eTypeOption values + + SBTypeFormat(const lldb::SBTypeFormat &rhs); + + ~SBTypeFormat(); + + bool IsValid() const; + + lldb::Format GetFormat(); + + const char *GetTypeName(); + + uint32_t GetOptions(); + + void SetFormat(lldb::Format); + + void SetTypeName(const char *); + + void SetOptions(uint32_t); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBTypeFormat &operator=(const lldb::SBTypeFormat &rhs); + + bool IsEqualTo(lldb::SBTypeFormat &rhs); + + bool operator==(lldb::SBTypeFormat &rhs); + + bool operator!=(lldb::SBTypeFormat &rhs); + +protected: + friend class SBDebugger; + friend class SBTypeCategory; + friend class SBValue; + + lldb::TypeFormatImplSP GetSP(); + + void SetSP(const lldb::TypeFormatImplSP &typeformat_impl_sp); + + lldb::TypeFormatImplSP m_opaque_sp; + + SBTypeFormat(const lldb::TypeFormatImplSP &); + + enum class Type { eTypeKeepSame, eTypeFormat, eTypeEnum }; + + bool CopyOnWrite_Impl(Type); +}; + +} // namespace lldb + +#endif // LLDB_SBTypeFormat_h_ diff --git a/include/lldb/API/SBTypeNameSpecifier.h b/include/lldb/API/SBTypeNameSpecifier.h new file mode 100644 index 000000000..2a4f09c20 --- /dev/null +++ b/include/lldb/API/SBTypeNameSpecifier.h @@ -0,0 +1,64 @@ +//===-- SBTypeNameSpecifier.h --------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBTypeNameSpecifier_h_ +#define LLDB_SBTypeNameSpecifier_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBTypeNameSpecifier { +public: + SBTypeNameSpecifier(); + + SBTypeNameSpecifier(const char *name, bool is_regex = false); + + SBTypeNameSpecifier(SBType type); + + SBTypeNameSpecifier(const lldb::SBTypeNameSpecifier &rhs); + + ~SBTypeNameSpecifier(); + + bool IsValid() const; + + const char *GetName(); + + SBType GetType(); + + bool IsRegex(); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBTypeNameSpecifier &operator=(const lldb::SBTypeNameSpecifier &rhs); + + bool IsEqualTo(lldb::SBTypeNameSpecifier &rhs); + + bool operator==(lldb::SBTypeNameSpecifier &rhs); + + bool operator!=(lldb::SBTypeNameSpecifier &rhs); + +protected: + friend class SBDebugger; + friend class SBTypeCategory; + + lldb::TypeNameSpecifierImplSP GetSP(); + + void SetSP(const lldb::TypeNameSpecifierImplSP &type_namespec_sp); + + lldb::TypeNameSpecifierImplSP m_opaque_sp; + + SBTypeNameSpecifier(const lldb::TypeNameSpecifierImplSP &); +}; + +} // namespace lldb + +#endif // LLDB_SBTypeNameSpecifier_h_ diff --git a/include/lldb/API/SBTypeSummary.h b/include/lldb/API/SBTypeSummary.h new file mode 100644 index 000000000..c9ccdff83 --- /dev/null +++ b/include/lldb/API/SBTypeSummary.h @@ -0,0 +1,136 @@ +//===-- SBTypeSummary.h -------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBTypeSummary_h_ +#define LLDB_SBTypeSummary_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { +class LLDB_API SBTypeSummaryOptions { +public: + SBTypeSummaryOptions(); + + SBTypeSummaryOptions(const lldb::SBTypeSummaryOptions &rhs); + + SBTypeSummaryOptions(const lldb_private::TypeSummaryOptions *lldb_object_ptr); + + ~SBTypeSummaryOptions(); + + bool IsValid(); + + lldb::LanguageType GetLanguage(); + + lldb::TypeSummaryCapping GetCapping(); + + void SetLanguage(lldb::LanguageType); + + void SetCapping(lldb::TypeSummaryCapping); + +protected: + friend class SBValue; + + lldb_private::TypeSummaryOptions *operator->(); + + const lldb_private::TypeSummaryOptions *operator->() const; + + lldb_private::TypeSummaryOptions *get(); + + lldb_private::TypeSummaryOptions &ref(); + + const lldb_private::TypeSummaryOptions &ref() const; + + void SetOptions(const lldb_private::TypeSummaryOptions *lldb_object_ptr); + +private: + std::unique_ptr m_opaque_ap; +}; + +class SBTypeSummary { +public: + SBTypeSummary(); + + // Native function summary formatter callback + typedef bool (*FormatCallback)(SBValue, SBTypeSummaryOptions, SBStream &); + + static SBTypeSummary + CreateWithSummaryString(const char *data, + uint32_t options = 0); // see lldb::eTypeOption values + + static SBTypeSummary + CreateWithFunctionName(const char *data, + uint32_t options = 0); // see lldb::eTypeOption values + + static SBTypeSummary + CreateWithScriptCode(const char *data, + uint32_t options = 0); // see lldb::eTypeOption values + + static SBTypeSummary CreateWithCallback(FormatCallback cb, + uint32_t options = 0, + const char *description = nullptr); + + SBTypeSummary(const lldb::SBTypeSummary &rhs); + + ~SBTypeSummary(); + + bool IsValid() const; + + bool IsFunctionCode(); + + bool IsFunctionName(); + + bool IsSummaryString(); + + const char *GetData(); + + void SetSummaryString(const char *data); + + void SetFunctionName(const char *data); + + void SetFunctionCode(const char *data); + + uint32_t GetOptions(); + + void SetOptions(uint32_t); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBTypeSummary &operator=(const lldb::SBTypeSummary &rhs); + + bool DoesPrintValue(lldb::SBValue value); + + bool IsEqualTo(lldb::SBTypeSummary &rhs); + + bool operator==(lldb::SBTypeSummary &rhs); + + bool operator!=(lldb::SBTypeSummary &rhs); + +protected: + friend class SBDebugger; + friend class SBTypeCategory; + friend class SBValue; + + lldb::TypeSummaryImplSP GetSP(); + + void SetSP(const lldb::TypeSummaryImplSP &typefilter_impl_sp); + + lldb::TypeSummaryImplSP m_opaque_sp; + + SBTypeSummary(const lldb::TypeSummaryImplSP &); + + bool CopyOnWrite_Impl(); + + bool ChangeSummaryType(bool want_script); +}; + +} // namespace lldb + +#endif // LLDB_SBTypeSummary_h_ diff --git a/include/lldb/API/SBTypeSynthetic.h b/include/lldb/API/SBTypeSynthetic.h new file mode 100644 index 000000000..2099df316 --- /dev/null +++ b/include/lldb/API/SBTypeSynthetic.h @@ -0,0 +1,83 @@ +//===-- SBTypeSynthetic.h -----------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBTypeSynthetic_h_ +#define LLDB_SBTypeSynthetic_h_ + +#include "lldb/API/SBDefines.h" + +#ifndef LLDB_DISABLE_PYTHON + +namespace lldb { + +class LLDB_API SBTypeSynthetic { +public: + SBTypeSynthetic(); + + static SBTypeSynthetic + CreateWithClassName(const char *data, + uint32_t options = 0); // see lldb::eTypeOption values + + static SBTypeSynthetic + CreateWithScriptCode(const char *data, + uint32_t options = 0); // see lldb::eTypeOption values + + SBTypeSynthetic(const lldb::SBTypeSynthetic &rhs); + + ~SBTypeSynthetic(); + + bool IsValid() const; + + bool IsClassCode(); + + bool IsClassName(); + + const char *GetData(); + + void SetClassName(const char *data); + + void SetClassCode(const char *data); + + uint32_t GetOptions(); + + void SetOptions(uint32_t); + + bool GetDescription(lldb::SBStream &description, + lldb::DescriptionLevel description_level); + + lldb::SBTypeSynthetic &operator=(const lldb::SBTypeSynthetic &rhs); + + bool IsEqualTo(lldb::SBTypeSynthetic &rhs); + + bool operator==(lldb::SBTypeSynthetic &rhs); + + bool operator!=(lldb::SBTypeSynthetic &rhs); + +protected: + friend class SBDebugger; + friend class SBTypeCategory; + friend class SBValue; + + lldb::ScriptedSyntheticChildrenSP GetSP(); + + void SetSP(const lldb::ScriptedSyntheticChildrenSP &typefilter_impl_sp); + + lldb::ScriptedSyntheticChildrenSP m_opaque_sp; + + SBTypeSynthetic(const lldb::ScriptedSyntheticChildrenSP &); + + bool CopyOnWrite_Impl(); +}; + +} // namespace lldb + +#endif // LLDB_DISABLE_PYTHON + +#endif // LLDB_SBTypeSynthetic_h_ diff --git a/include/lldb/API/SBUnixSignals.h b/include/lldb/API/SBUnixSignals.h new file mode 100644 index 000000000..d44a508fb --- /dev/null +++ b/include/lldb/API/SBUnixSignals.h @@ -0,0 +1,70 @@ +//===-- SBUnixSignals.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_SBUnixSignals_h_ +#define LLDB_SBUnixSignals_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBUnixSignals { +public: + SBUnixSignals(); + + SBUnixSignals(const lldb::SBUnixSignals &rhs); + + ~SBUnixSignals(); + + const SBUnixSignals &operator=(const lldb::SBUnixSignals &rhs); + + void Clear(); + + bool IsValid() const; + + const char *GetSignalAsCString(int32_t signo) const; + + int32_t GetSignalNumberFromName(const char *name) const; + + bool GetShouldSuppress(int32_t signo) const; + + bool SetShouldSuppress(int32_t signo, bool value); + + bool GetShouldStop(int32_t signo) const; + + bool SetShouldStop(int32_t signo, bool value); + + bool GetShouldNotify(int32_t signo) const; + + bool SetShouldNotify(int32_t signo, bool value); + + int32_t GetNumSignals() const; + + int32_t GetSignalAtIndex(int32_t index) const; + +protected: + friend class SBProcess; + friend class SBPlatform; + + SBUnixSignals(lldb::ProcessSP &process_sp); + + SBUnixSignals(lldb::PlatformSP &platform_sp); + + lldb::UnixSignalsSP GetSP() const; + + void SetSP(const lldb::UnixSignalsSP &signals_sp); + +private: + lldb::UnixSignalsWP m_opaque_wp; +}; + +} // namespace lldb + +#endif // LLDB_SBUnixSignals_h_ diff --git a/include/lldb/API/SBValue.h b/include/lldb/API/SBValue.h new file mode 100644 index 000000000..5ef8915b5 --- /dev/null +++ b/include/lldb/API/SBValue.h @@ -0,0 +1,446 @@ +//===-- SBValue.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBValue_h_ +#define LLDB_SBValue_h_ + +#include "lldb/API/SBData.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBType.h" + +class ValueImpl; +class ValueLocker; + +namespace lldb { + +class LLDB_API SBValue { +public: + SBValue(); + + SBValue(const lldb::SBValue &rhs); + + lldb::SBValue &operator=(const lldb::SBValue &rhs); + + ~SBValue(); + + bool IsValid(); + + void Clear(); + + SBError GetError(); + + lldb::user_id_t GetID(); + + const char *GetName(); + + const char *GetTypeName(); + + const char *GetDisplayTypeName(); + + size_t GetByteSize(); + + bool IsInScope(); + + lldb::Format GetFormat(); + + void SetFormat(lldb::Format format); + + const char *GetValue(); + + int64_t GetValueAsSigned(lldb::SBError &error, int64_t fail_value = 0); + + uint64_t GetValueAsUnsigned(lldb::SBError &error, uint64_t fail_value = 0); + + int64_t GetValueAsSigned(int64_t fail_value = 0); + + uint64_t GetValueAsUnsigned(uint64_t fail_value = 0); + + ValueType GetValueType(); + + // If you call this on a newly created ValueObject, it will always return + // false. + bool GetValueDidChange(); + + const char *GetSummary(); + + const char *GetSummary(lldb::SBStream &stream, + lldb::SBTypeSummaryOptions &options); + + const char *GetObjectDescription(); + + const char *GetTypeValidatorResult(); + + lldb::SBValue GetDynamicValue(lldb::DynamicValueType use_dynamic); + + lldb::SBValue GetStaticValue(); + + lldb::SBValue GetNonSyntheticValue(); + + lldb::DynamicValueType GetPreferDynamicValue(); + + void SetPreferDynamicValue(lldb::DynamicValueType use_dynamic); + + bool GetPreferSyntheticValue(); + + void SetPreferSyntheticValue(bool use_synthetic); + + bool IsDynamic(); + + bool IsSynthetic(); + + bool IsSyntheticChildrenGenerated(); + + void SetSyntheticChildrenGenerated(bool); + + const char *GetLocation(); + + // Deprecated - use the one that takes SBError& + bool SetValueFromCString(const char *value_str); + + bool SetValueFromCString(const char *value_str, lldb::SBError &error); + + lldb::SBTypeFormat GetTypeFormat(); + + lldb::SBTypeSummary GetTypeSummary(); + + lldb::SBTypeFilter GetTypeFilter(); + +#ifndef LLDB_DISABLE_PYTHON + lldb::SBTypeSynthetic GetTypeSynthetic(); +#endif + + lldb::SBValue GetChildAtIndex(uint32_t idx); + + lldb::SBValue CreateChildAtOffset(const char *name, uint32_t offset, + lldb::SBType type); + + // Deprecated - use the expression evaluator to perform type casting + lldb::SBValue Cast(lldb::SBType type); + + lldb::SBValue CreateValueFromExpression(const char *name, + const char *expression); + + lldb::SBValue CreateValueFromExpression(const char *name, + const char *expression, + SBExpressionOptions &options); + + lldb::SBValue CreateValueFromAddress(const char *name, lldb::addr_t address, + lldb::SBType type); + + // this has no address! GetAddress() and GetLoadAddress() as well as + // AddressOf() + // on the return of this call all return invalid + lldb::SBValue CreateValueFromData(const char *name, lldb::SBData data, + lldb::SBType type); + + //------------------------------------------------------------------ + /// Get a child value by index from a value. + /// + /// Structs, unions, classes, arrays and pointers have child + /// values that can be access by index. + /// + /// Structs and unions access child members using a zero based index + /// for each child member. For + /// + /// Classes reserve the first indexes for base classes that have + /// members (empty base classes are omitted), and all members of the + /// current class will then follow the base classes. + /// + /// Pointers differ depending on what they point to. If the pointer + /// points to a simple type, the child at index zero + /// is the only child value available, unless \a synthetic_allowed + /// is \b true, in which case the pointer will be used as an array + /// and can create 'synthetic' child values using positive or + /// negative indexes. If the pointer points to an aggregate type + /// (an array, class, union, struct), then the pointee is + /// transparently skipped and any children are going to be the indexes + /// of the child values within the aggregate type. For example if + /// we have a 'Point' type and we have a SBValue that contains a + /// pointer to a 'Point' type, then the child at index zero will be + /// the 'x' member, and the child at index 1 will be the 'y' member + /// (the child at index zero won't be a 'Point' instance). + /// + /// If you actually need an SBValue that represents the type pointed + /// to by a SBValue for which GetType().IsPointeeType() returns true, + /// regardless of the pointee type, you can do that with SBValue::Dereference. + /// + /// Arrays have a preset number of children that can be accessed by + /// index and will returns invalid child values for indexes that are + /// out of bounds unless the \a synthetic_allowed is \b true. In this + /// case the array can create 'synthetic' child values for indexes + /// that aren't in the array bounds using positive or negative + /// indexes. + /// + /// @param[in] idx + /// The index of the child value to get + /// + /// @param[in] use_dynamic + /// An enumeration that specifies whether to get dynamic values, + /// and also if the target can be run to figure out the dynamic + /// type of the child value. + /// + /// @param[in] can_create_synthetic + /// If \b true, then allow child values to be created by index + /// for pointers and arrays for indexes that normally wouldn't + /// be allowed. + /// + /// @return + /// A new SBValue object that represents the child member value. + //------------------------------------------------------------------ + lldb::SBValue GetChildAtIndex(uint32_t idx, + lldb::DynamicValueType use_dynamic, + bool can_create_synthetic); + + // Matches children of this object only and will match base classes and + // member names if this is a clang typed object. + uint32_t GetIndexOfChildWithName(const char *name); + + // Matches child members of this object and child members of any base + // classes. + lldb::SBValue GetChildMemberWithName(const char *name); + + // Matches child members of this object and child members of any base + // classes. + lldb::SBValue GetChildMemberWithName(const char *name, + lldb::DynamicValueType use_dynamic); + + // Expands nested expressions like .a->b[0].c[1]->d + lldb::SBValue GetValueForExpressionPath(const char *expr_path); + + lldb::SBValue AddressOf(); + + lldb::addr_t GetLoadAddress(); + + lldb::SBAddress GetAddress(); + + //------------------------------------------------------------------ + /// Get an SBData wrapping what this SBValue points to. + /// + /// This method will dereference the current SBValue, if its + /// data type is a T* or T[], and extract item_count elements + /// of type T from it, copying their contents in an SBData. + /// + /// @param[in] item_idx + /// The index of the first item to retrieve. For an array + /// this is equivalent to array[item_idx], for a pointer + /// to *(pointer + item_idx). In either case, the measurement + /// unit for item_idx is the sizeof(T) rather than the byte + /// + /// @param[in] item_count + /// How many items should be copied into the output. By default + /// only one item is copied, but more can be asked for. + /// + /// @return + /// An SBData with the contents of the copied items, on success. + /// An empty SBData otherwise. + //------------------------------------------------------------------ + lldb::SBData GetPointeeData(uint32_t item_idx = 0, uint32_t item_count = 1); + + //------------------------------------------------------------------ + /// Get an SBData wrapping the contents of this SBValue. + /// + /// This method will read the contents of this object in memory + /// and copy them into an SBData for future use. + /// + /// @return + /// An SBData with the contents of this SBValue, on success. + /// An empty SBData otherwise. + //------------------------------------------------------------------ + lldb::SBData GetData(); + + bool SetData(lldb::SBData &data, lldb::SBError &error); + + lldb::SBDeclaration GetDeclaration(); + + //------------------------------------------------------------------ + /// Find out if a SBValue might have children. + /// + /// This call is much more efficient than GetNumChildren() as it + /// doesn't need to complete the underlying type. This is designed + /// to be used in a UI environment in order to detect if the + /// disclosure triangle should be displayed or not. + /// + /// This function returns true for class, union, structure, + /// pointers, references, arrays and more. Again, it does so without + /// doing any expensive type completion. + /// + /// @return + /// Returns \b true if the SBValue might have children, or \b + /// false otherwise. + //------------------------------------------------------------------ + bool MightHaveChildren(); + + bool IsRuntimeSupportValue(); + + uint32_t GetNumChildren(); + + uint32_t GetNumChildren(uint32_t max); + + void *GetOpaqueType(); + + lldb::SBTarget GetTarget(); + + lldb::SBProcess GetProcess(); + + lldb::SBThread GetThread(); + + lldb::SBFrame GetFrame(); + + lldb::SBValue Dereference(); + + // Deprecated - please use GetType().IsPointerType() instead. + bool TypeIsPointerType(); + + lldb::SBType GetType(); + + lldb::SBValue Persist(); + + bool GetDescription(lldb::SBStream &description); + + bool GetExpressionPath(lldb::SBStream &description); + + bool GetExpressionPath(lldb::SBStream &description, + bool qualify_cxx_base_classes); + + SBValue(const lldb::ValueObjectSP &value_sp); + + //------------------------------------------------------------------ + /// Watch this value if it resides in memory. + /// + /// Sets a watchpoint on the value. + /// + /// @param[in] resolve_location + /// Resolve the location of this value once and watch its address. + /// This value must currently be set to \b true as watching all + /// locations of a variable or a variable path is not yet supported, + /// though we plan to support it in the future. + /// + /// @param[in] read + /// Stop when this value is accessed. + /// + /// @param[in] write + /// Stop when this value is modified + /// + /// @param[out] error + /// An error object. Contains the reason if there is some failure. + /// + /// @return + /// An SBWatchpoint object. This object might not be valid upon + /// return due to a value not being contained in memory, too + /// large, or watchpoint resources are not available or all in + /// use. + //------------------------------------------------------------------ + lldb::SBWatchpoint Watch(bool resolve_location, bool read, bool write, + SBError &error); + + // Backward compatibility fix in the interim. + lldb::SBWatchpoint Watch(bool resolve_location, bool read, bool write); + + //------------------------------------------------------------------ + /// Watch this value that this value points to in memory + /// + /// Sets a watchpoint on the value. + /// + /// @param[in] resolve_location + /// Resolve the location of this value once and watch its address. + /// This value must currently be set to \b true as watching all + /// locations of a variable or a variable path is not yet supported, + /// though we plan to support it in the future. + /// + /// @param[in] read + /// Stop when this value is accessed. + /// + /// @param[in] write + /// Stop when this value is modified + /// + /// @param[out] error + /// An error object. Contains the reason if there is some failure. + /// + /// @return + /// An SBWatchpoint object. This object might not be valid upon + /// return due to a value not being contained in memory, too + /// large, or watchpoint resources are not available or all in + /// use. + //------------------------------------------------------------------ + lldb::SBWatchpoint WatchPointee(bool resolve_location, bool read, bool write, + SBError &error); + + //------------------------------------------------------------------ + /// Same as the protected version of GetSP that takes a locker, except that we + /// make the + /// locker locally in the function. Since the Target API mutex is recursive, + /// and the + /// StopLocker is a read lock, you can call this function even if you are + /// already + /// holding the two above-mentioned locks. + /// + /// @return + /// A ValueObjectSP of the best kind (static, dynamic or synthetic) we + /// can cons up, in accordance with the SBValue's settings. + //------------------------------------------------------------------ + lldb::ValueObjectSP GetSP() const; + +protected: + friend class SBBlock; + friend class SBFrame; + friend class SBTarget; + friend class SBThread; + friend class SBValueList; + + //------------------------------------------------------------------ + /// Get the appropriate ValueObjectSP from this SBValue, consulting the + /// use_dynamic and use_synthetic options passed in to SetSP when the + /// SBValue's contents were set. Since this often requires examining memory, + /// and maybe even running code, it needs to acquire the Target API and + /// Process StopLock. + /// Those are held in an opaque class ValueLocker which is currently local to + /// SBValue.cpp. + /// So you don't have to get these yourself just default construct a + /// ValueLocker, and pass it into this. + /// If we need to make a ValueLocker and use it in some other .cpp file, we'll + /// have to move it to + /// ValueObject.h/cpp or somewhere else convenient. We haven't needed to so + /// far. + /// + /// @param[in] value_locker + /// An object that will hold the Target API, and Process RunLocks, and + /// auto-destroy them when it goes out of scope. Currently this is only + /// useful in + /// SBValue.cpp. + /// + /// @return + /// A ValueObjectSP of the best kind (static, dynamic or synthetic) we + /// can cons up, in accordance with the SBValue's settings. + //------------------------------------------------------------------ + lldb::ValueObjectSP GetSP(ValueLocker &value_locker) const; + + // these calls do the right thing WRT adjusting their settings according to + // the target's preferences + void SetSP(const lldb::ValueObjectSP &sp); + + void SetSP(const lldb::ValueObjectSP &sp, bool use_synthetic); + + void SetSP(const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic); + + void SetSP(const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, + bool use_synthetic); + + void SetSP(const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, + bool use_synthetic, const char *name); + +private: + typedef std::shared_ptr ValueImplSP; + ValueImplSP m_opaque_sp; + + void SetSP(ValueImplSP impl_sp); +}; + +} // namespace lldb + +#endif // LLDB_SBValue_h_ diff --git a/include/lldb/API/SBValueList.h b/include/lldb/API/SBValueList.h new file mode 100644 index 000000000..495b0140c --- /dev/null +++ b/include/lldb/API/SBValueList.h @@ -0,0 +1,74 @@ +//===-- SBValueList.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBValueList_h_ +#define LLDB_SBValueList_h_ + +#include "lldb/API/SBDefines.h" + +class ValueListImpl; + +namespace lldb { + +class LLDB_API SBValueList { +public: + SBValueList(); + + SBValueList(const lldb::SBValueList &rhs); + + ~SBValueList(); + + bool IsValid() const; + + void Clear(); + + void Append(const lldb::SBValue &val_obj); + + void Append(const lldb::SBValueList &value_list); + + uint32_t GetSize() const; + + lldb::SBValue GetValueAtIndex(uint32_t idx) const; + + lldb::SBValue GetFirstValueByName(const char *name) const; + + lldb::SBValue FindValueObjectByUID(lldb::user_id_t uid); + + const lldb::SBValueList &operator=(const lldb::SBValueList &rhs); + +protected: + // only useful for visualizing the pointer or comparing two SBValueLists + // to see if they are backed by the same underlying Impl. + void *opaque_ptr(); + +private: + friend class SBFrame; + + SBValueList(const ValueListImpl *lldb_object_ptr); + + void Append(lldb::ValueObjectSP &val_obj_sp); + + void CreateIfNeeded(); + + ValueListImpl *operator->(); + + ValueListImpl &operator*(); + + const ValueListImpl *operator->() const; + + const ValueListImpl &operator*() const; + + ValueListImpl &ref(); + + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBValueList_h_ diff --git a/include/lldb/API/SBVariablesOptions.h b/include/lldb/API/SBVariablesOptions.h new file mode 100644 index 000000000..756da6439 --- /dev/null +++ b/include/lldb/API/SBVariablesOptions.h @@ -0,0 +1,77 @@ +//===-- SBVariablesOptions.h ------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBVariablesOptions_h_ +#define LLDB_SBVariablesOptions_h_ + +#include "lldb/API/SBDefines.h" + +class VariablesOptionsImpl; + +namespace lldb { + +class LLDB_API SBVariablesOptions { +public: + SBVariablesOptions(); + + SBVariablesOptions(const SBVariablesOptions &options); + + SBVariablesOptions &operator=(const SBVariablesOptions &options); + + ~SBVariablesOptions(); + + bool IsValid() const; + + bool GetIncludeArguments() const; + + void SetIncludeArguments(bool); + + bool GetIncludeLocals() const; + + void SetIncludeLocals(bool); + + bool GetIncludeStatics() const; + + void SetIncludeStatics(bool); + + bool GetInScopeOnly() const; + + void SetInScopeOnly(bool); + + bool GetIncludeRuntimeSupportValues() const; + + void SetIncludeRuntimeSupportValues(bool); + + lldb::DynamicValueType GetUseDynamic() const; + + void SetUseDynamic(lldb::DynamicValueType); + +protected: + VariablesOptionsImpl *operator->(); + + const VariablesOptionsImpl *operator->() const; + + VariablesOptionsImpl *get(); + + VariablesOptionsImpl &ref(); + + const VariablesOptionsImpl &ref() const; + + SBVariablesOptions(VariablesOptionsImpl *lldb_object_ptr); + + void SetOptions(VariablesOptionsImpl *lldb_object_ptr); + +private: + std::unique_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBValue_h_ diff --git a/include/lldb/API/SBWatchpoint.h b/include/lldb/API/SBWatchpoint.h new file mode 100644 index 000000000..92d4851fc --- /dev/null +++ b/include/lldb/API/SBWatchpoint.h @@ -0,0 +1,80 @@ +//===-- SBWatchpoint.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBWatchpoint_h_ +#define LLDB_SBWatchpoint_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBWatchpoint { +public: + SBWatchpoint(); + + SBWatchpoint(const lldb::SBWatchpoint &rhs); + + SBWatchpoint(const lldb::WatchpointSP &wp_sp); + + ~SBWatchpoint(); + + const lldb::SBWatchpoint &operator=(const lldb::SBWatchpoint &rhs); + + bool IsValid() const; + + SBError GetError(); + + watch_id_t GetID(); + + /// With -1 representing an invalid hardware index. + int32_t GetHardwareIndex(); + + lldb::addr_t GetWatchAddress(); + + size_t GetWatchSize(); + + void SetEnabled(bool enabled); + + bool IsEnabled(); + + uint32_t GetHitCount(); + + uint32_t GetIgnoreCount(); + + void SetIgnoreCount(uint32_t n); + + const char *GetCondition(); + + void SetCondition(const char *condition); + + bool GetDescription(lldb::SBStream &description, DescriptionLevel level); + + void Clear(); + + lldb::WatchpointSP GetSP() const; + + void SetSP(const lldb::WatchpointSP &sp); + + static bool EventIsWatchpointEvent(const lldb::SBEvent &event); + + static lldb::WatchpointEventType + GetWatchpointEventTypeFromEvent(const lldb::SBEvent &event); + + static lldb::SBWatchpoint GetWatchpointFromEvent(const lldb::SBEvent &event); + +private: + friend class SBTarget; + friend class SBValue; + + std::weak_ptr m_opaque_wp; +}; + +} // namespace lldb + +#endif // LLDB_SBWatchpoint_h_ diff --git a/include/lldb/API/SystemInitializerFull.h b/include/lldb/API/SystemInitializerFull.h new file mode 100644 index 000000000..9cfc6896d --- /dev/null +++ b/include/lldb/API/SystemInitializerFull.h @@ -0,0 +1,38 @@ +//===-- SystemInitializerFull.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_API_SYSTEM_INITIALIZER_FULL_H +#define LLDB_API_SYSTEM_INITIALIZER_FULL_H + +#include "lldb/Initialization/SystemInitializerCommon.h" + +namespace lldb_private { +//------------------------------------------------------------------ +/// Initializes lldb. +/// +/// This class is responsible for initializing all of lldb system +/// services needed to use the full LLDB application. This class is +/// not intended to be used externally, but is instead used +/// internally by SBDebugger to initialize the system. +//------------------------------------------------------------------ +class SystemInitializerFull : public SystemInitializerCommon { +public: + SystemInitializerFull(); + ~SystemInitializerFull() override; + + void Initialize() override; + void Terminate() override; + +private: + void InitializeSWIG(); +}; + +} // namespace lldb_private + +#endif // LLDB_API_SYSTEM_INITIALIZER_FULL_H diff --git a/include/lldb/Breakpoint/Breakpoint.h b/include/lldb/Breakpoint/Breakpoint.h new file mode 100644 index 000000000..41241334d --- /dev/null +++ b/include/lldb/Breakpoint/Breakpoint.h @@ -0,0 +1,763 @@ +//===-- 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 +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/Breakpoint/BreakpointLocationCollection.h" +#include "lldb/Breakpoint/BreakpointLocationList.h" +#include "lldb/Breakpoint/BreakpointOptions.h" +#include "lldb/Breakpoint/Stoppoint.h" +#include "lldb/Core/Event.h" +#include "lldb/Core/SearchFilter.h" +#include "lldb/Utility/StringList.h" +#include "lldb/Utility/StructuredData.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Breakpoint Breakpoint.h "lldb/Breakpoint/Breakpoint.h" +/// @brief Class that manages logical breakpoint setting. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +/// General Outline: +/// A breakpoint has four main parts, a filter, a resolver, the list of +/// breakpoint +/// locations that have been determined for the filter/resolver pair, and +/// finally +/// a set of options for the breakpoint. +/// +/// \b Filter: +/// This is an object derived from SearchFilter. It manages the search +/// for breakpoint location matches through the symbols in the module list of +/// the target +/// that owns it. It also filters out locations based on whatever logic it +/// wants. +/// +/// \b Resolver: +/// This is an object derived from BreakpointResolver. It provides a +/// callback to the filter that will find breakpoint locations. How it does +/// this is +/// determined by what kind of resolver it is. +/// +/// The Breakpoint class also provides constructors for the common breakpoint +/// cases +/// which make the appropriate filter and resolver for you. +/// +/// \b Location List: +/// This stores the breakpoint locations that have been determined +/// to date. For a given breakpoint, there will be only one location with a +/// given +/// address. Adding a location at an already taken address will just return the +/// location +/// already at that address. Locations can be looked up by ID, or by address. +/// +/// \b Options: +/// This includes: +/// \b Enabled/Disabled +/// \b Ignore Count +/// \b Callback +/// \b Condition +/// Note, these options can be set on the breakpoint, and they can also be set +/// on the +/// individual locations. The options set on the breakpoint take precedence +/// over the +/// options set on the individual location. +/// So for instance disabling the breakpoint will cause NONE of the locations to +/// get hit. +/// But if the breakpoint is enabled, then the location's enabled state will be +/// checked +/// to determine whether to insert that breakpoint location. +/// Similarly, if the breakpoint condition says "stop", we won't check the +/// location's condition. +/// But if the breakpoint condition says "continue", then we will check the +/// location for whether +/// to actually stop or not. +/// One subtle point worth observing here is that you don't actually stop at a +/// Breakpoint, you +/// always stop at one of its locations. So the "should stop" tests are done by +/// the location, +/// not by the breakpoint. +//---------------------------------------------------------------------- +class Breakpoint : public std::enable_shared_from_this, + 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; + +private: + enum class OptionNames : uint32_t { Names = 0, Hardware, LastOptionName }; + + static const char + *g_option_names[static_cast(OptionNames::LastOptionName)]; + + static const char *GetKey(OptionNames enum_value) { + return g_option_names[static_cast(enum_value)]; + } + +public: + class BreakpointEventData : public EventData { + public: + BreakpointEventData(lldb::BreakpointEventType sub_type, + const lldb::BreakpointSP &new_breakpoint_sp); + + ~BreakpointEventData() override; + + static const ConstString &GetFlavorString(); + + const ConstString &GetFlavor() const override; + + lldb::BreakpointEventType GetBreakpointEventType() const; + + lldb::BreakpointSP &GetBreakpoint(); + + BreakpointLocationCollection &GetBreakpointLocationCollection() { + return m_locations; + } + + void Dump(Stream *s) const override; + + static lldb::BreakpointEventType + GetBreakpointEventTypeFromEvent(const lldb::EventSP &event_sp); + + static lldb::BreakpointSP + GetBreakpointFromEvent(const lldb::EventSP &event_sp); + + static lldb::BreakpointLocationSP + GetBreakpointLocationAtIndexFromEvent(const lldb::EventSP &event_sp, + uint32_t loc_idx); + + static size_t + GetNumBreakpointLocationsFromEvent(const lldb::EventSP &event_sp); + + static const BreakpointEventData * + GetEventDataFromEvent(const Event *event_sp); + + private: + lldb::BreakpointEventType m_breakpoint_event; + lldb::BreakpointSP m_new_breakpoint_sp; + BreakpointLocationCollection m_locations; + + DISALLOW_COPY_AND_ASSIGN(BreakpointEventData); + }; + + class BreakpointPrecondition { + public: + virtual ~BreakpointPrecondition() = default; + + virtual bool EvaluatePrecondition(StoppointCallbackContext &context); + + virtual Status ConfigurePrecondition(Args &options); + + virtual void GetDescription(Stream &stream, lldb::DescriptionLevel level); + }; + + typedef std::shared_ptr BreakpointPreconditionSP; + + // Saving & restoring breakpoints: + static lldb::BreakpointSP CreateFromStructuredData( + Target &target, StructuredData::ObjectSP &data_object_sp, Status &error); + + static bool + SerializedBreakpointMatchesNames(StructuredData::ObjectSP &bkpt_object_sp, + std::vector &names); + + virtual StructuredData::ObjectSP SerializeToStructuredData(); + + static const char *GetSerializationKey() { return "Breakpoint"; } + //------------------------------------------------------------------ + /// 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() override; + + //------------------------------------------------------------------ + // 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) override; + + //------------------------------------------------------------------ + // 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] module_list + /// The list of modules to look in for new locations. + /// + /// @param[in] send_event + /// If \b true, send a breakpoint location added event for non-internal + /// breakpoints. + //------------------------------------------------------------------ + void ResolveBreakpointInModules(ModuleList &module_list, + bool send_event = true); + + //------------------------------------------------------------------ + /// Tell this breakpoint to scan a given module list and resolve any + /// new locations that match the breakpoint's specifications. + /// + /// @param[in] changed_modules + /// The list of modules to look in for new locations. + /// + /// @param[in] new_locations + /// Fills new_locations with the new locations that were made. + //------------------------------------------------------------------ + void ResolveBreakpointInModules(ModuleList &module_list, + BreakpointLocationCollection &new_locations); + + //------------------------------------------------------------------ + /// Like ResolveBreakpointInModules, but allows for "unload" events, in + /// which case we will remove any locations that are in modules that got + /// unloaded. + /// + /// @param[in] changedModules + /// The list of modules to look in for new locations. + /// @param[in] load_event + /// If \b true then the modules were loaded, if \b false, unloaded. + /// @param[in] delete_locations + /// If \b true then the modules were unloaded delete any locations in the + /// changed modules. + //------------------------------------------------------------------ + void ModulesChanged(ModuleList &changed_modules, bool load_event, + bool delete_locations = false); + + //------------------------------------------------------------------ + /// Tells the breakpoint the old module \a old_module_sp has been + /// replaced by new_module_sp (usually because the underlying file has been + /// rebuilt, and the old version is gone.) + /// + /// @param[in] old_module_sp + /// The old module that is going away. + /// @param[in] new_module_sp + /// The new module that is replacing it. + //------------------------------------------------------------------ + void ModuleReplaced(lldb::ModuleSP old_module_sp, + lldb::ModuleSP new_module_sp); + + //------------------------------------------------------------------ + // The next set of methods provide access to the breakpoint locations + // for this breakpoint. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Add a location to the breakpoint's location list. This is only meant + /// to be called by the breakpoint's resolver. FIXME: how do I ensure that? + /// + /// @param[in] addr + /// The Address specifying the new location. + /// @param[out] new_location + /// Set to \b true if a new location was created, to \b false if there + /// already was a location at this Address. + /// @return + /// Returns a pointer to the new location. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP AddLocation(const Address &addr, + bool *new_location = nullptr); + + //------------------------------------------------------------------ + /// 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 nullptr if there is no location at that + /// address. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP FindLocationByAddress(const Address &addr); + + //------------------------------------------------------------------ + /// Find a breakpoint location ID by Address. + /// + /// @param[in] addr + /// The Address specifying the location. + /// @return + /// Returns the UID of the location at \a addr, or \b LLDB_INVALID_ID if + /// there is no breakpoint location at that address. + //------------------------------------------------------------------ + lldb::break_id_t FindLocationIDByAddress(const Address &addr); + + //------------------------------------------------------------------ + /// Find a breakpoint location for a given breakpoint location ID. + /// + /// @param[in] bp_loc_id + /// The ID specifying the location. + /// @return + /// Returns a shared pointer to the location with ID \a bp_loc_id. The + /// pointer + /// in the shared pointer will be nullptr 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 nullptr if \a index is + /// greater than then number of actual locations. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP GetLocationAtIndex(size_t index); + + //------------------------------------------------------------------ + /// Removes all invalid breakpoint locations. + /// + /// Removes all breakpoint locations with architectures that aren't + /// compatible with \a arch. Also remove any breakpoint locations + /// with whose locations have address where the section has been + /// deleted (module and object files no longer exist). + /// + /// This is typically used after the process calls exec, or anytime + /// the architecture of the target changes. + /// + /// @param[in] arch + /// If valid, check the module in each breakpoint to make sure + /// they are compatible, otherwise, ignore architecture. + //------------------------------------------------------------------ + void RemoveInvalidLocations(const ArchSpec &arch); + + //------------------------------------------------------------------ + // 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) override; + + //------------------------------------------------------------------ + /// Check the Enable/Disable state. + /// @return + /// \b true if the breakpoint is enabled, \b false if disabled. + //------------------------------------------------------------------ + bool IsEnabled() override; + + //------------------------------------------------------------------ + /// Set the breakpoint to ignore the next \a count breakpoint hits. + /// @param[in] count + /// The number of breakpoint hits to ignore. + //------------------------------------------------------------------ + void SetIgnoreCount(uint32_t count); + + //------------------------------------------------------------------ + /// Return the current ignore count/ + /// @return + /// The number of breakpoint hits to be ignored. + //------------------------------------------------------------------ + uint32_t GetIgnoreCount() const; + + //------------------------------------------------------------------ + /// Return the current hit count for all locations. + /// @return + /// The current hit count for all locations. + //------------------------------------------------------------------ + uint32_t GetHitCount() const; + + //------------------------------------------------------------------ + /// If \a one_shot is \b true, breakpoint will be deleted on first hit. + //------------------------------------------------------------------ + void SetOneShot(bool one_shot); + + //------------------------------------------------------------------ + /// Check the OneShot state. + /// @return + /// \b true if the breakpoint is one shot, \b false otherwise. + //------------------------------------------------------------------ + bool IsOneShot() const; + + //------------------------------------------------------------------ + /// Set the valid thread to be checked when the breakpoint is hit. + /// @param[in] thread_id + /// If this thread hits the breakpoint, we stop, otherwise not. + //------------------------------------------------------------------ + void SetThreadID(lldb::tid_t thread_id); + + //------------------------------------------------------------------ + /// Return the current stop thread value. + /// @return + /// The thread id for which the breakpoint hit will stop, + /// LLDB_INVALID_THREAD_ID for all threads. + //------------------------------------------------------------------ + lldb::tid_t GetThreadID() const; + + void SetThreadIndex(uint32_t index); + + uint32_t GetThreadIndex() const; + + void SetThreadName(const char *thread_name); + + const char *GetThreadName() const; + + void SetQueueName(const char *queue_name); + + const char *GetQueueName() const; + + //------------------------------------------------------------------ + /// Set the callback action invoked when the breakpoint is hit. + /// + /// @param[in] callback + /// The method that will get called when the breakpoint is hit. + /// @param[in] baton + /// A void * pointer that will get passed back to the callback function. + /// @param[in] is_synchronous + /// If \b true the callback will be run on the private event thread + /// before the stop event gets reported. If false, the callback will get + /// handled on the public event thread after the stop has been posted. + /// + /// @return + /// \b true if the process should stop when you hit the breakpoint. + /// \b false if it should continue. + //------------------------------------------------------------------ + void SetCallback(BreakpointHitCallback callback, void *baton, + bool is_synchronous = false); + + void SetCallback(BreakpointHitCallback callback, + const lldb::BatonSP &callback_baton_sp, + bool is_synchronous = false); + + void ClearCallback(); + + //------------------------------------------------------------------ + /// Set the breakpoint's condition. + /// + /// @param[in] condition + /// The condition expression to evaluate when the breakpoint is hit. + /// Pass in nullptr to clear the condition. + //------------------------------------------------------------------ + void SetCondition(const char *condition); + + //------------------------------------------------------------------ + /// Return a pointer to the text of the condition expression. + /// + /// @return + /// A pointer to the condition expression text, or nullptr if no + // condition has been set. + //------------------------------------------------------------------ + const char *GetConditionText() const; + + //------------------------------------------------------------------ + // The next section are various utility functions. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Return the number of breakpoint locations that have resolved to + /// actual breakpoint sites. + /// + /// @return + /// The number locations resolved breakpoint sites. + //------------------------------------------------------------------ + size_t GetNumResolvedLocations() const; + + //------------------------------------------------------------------ + /// Return the number of breakpoint locations. + /// + /// @return + /// The number breakpoint locations. + //------------------------------------------------------------------ + size_t GetNumLocations() const; + + //------------------------------------------------------------------ + /// Put a description of this breakpoint into the stream \a s. + /// + /// @param[in] s + /// Stream into which to dump the description. + /// + /// @param[in] level + /// The description level that indicates the detail level to + /// provide. + /// + /// @see lldb::DescriptionLevel + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level, + bool show_locations = false); + + //------------------------------------------------------------------ + /// Set the "kind" description for a breakpoint. If the breakpoint is hit + /// the stop info will show this "kind" description instead of the breakpoint + /// number. Mostly useful for internal breakpoints, where the breakpoint + /// number + /// doesn't have meaning to the user. + /// + /// @param[in] kind + /// New "kind" description. + //------------------------------------------------------------------ + void SetBreakpointKind(const char *kind) { m_kind_description.assign(kind); } + + //------------------------------------------------------------------ + /// Return the "kind" description for a breakpoint. + /// + /// @return + /// The breakpoint kind, or nullptr if none is set. + //------------------------------------------------------------------ + const char *GetBreakpointKind() const { return m_kind_description.c_str(); } + + //------------------------------------------------------------------ + /// Accessor for the breakpoint Target. + /// @return + /// This breakpoint's Target. + //------------------------------------------------------------------ + Target &GetTarget() { return m_target; } + + const Target &GetTarget() const { return m_target; } + + const lldb::TargetSP GetTargetSP(); + + void GetResolverDescription(Stream *s); + + //------------------------------------------------------------------ + /// Find breakpoint locations which match the (filename, line_number) + /// description. + /// The breakpoint location collection is to be filled with the matching + /// locations. + /// It should be initialized with 0 size by the API client. + /// + /// @return + /// True if there is a match + /// + /// The locations which match the filename and line_number in loc_coll. + /// If its + /// size is 0 and true is returned, it means the breakpoint fully matches + /// the + /// description. + //------------------------------------------------------------------ + bool GetMatchingFileLine(const ConstString &filename, uint32_t line_number, + BreakpointLocationCollection &loc_coll); + + void GetFilterDescription(Stream *s); + + //------------------------------------------------------------------ + /// Returns the BreakpointOptions structure set at the breakpoint level. + /// + /// Meant to be used by the BreakpointLocation class. + /// + /// @return + /// A pointer to this breakpoint's BreakpointOptions. + //------------------------------------------------------------------ + BreakpointOptions *GetOptions(); + + //------------------------------------------------------------------ + /// Invoke the callback action when the breakpoint is hit. + /// + /// Meant to be used by the BreakpointLocation class. + /// + /// @param[in] context + /// Described the breakpoint event. + /// + /// @param[in] bp_loc_id + /// Which breakpoint location hit this breakpoint. + /// + /// @return + /// \b true if the target should stop at this breakpoint and \b false not. + //------------------------------------------------------------------ + bool InvokeCallback(StoppointCallbackContext *context, + lldb::break_id_t bp_loc_id); + + bool IsHardware() const { return m_hardware; } + + lldb::BreakpointResolverSP GetResolver() { return m_resolver_sp; } + + lldb::SearchFilterSP GetSearchFilter() { return m_filter_sp; } + + bool AddName(llvm::StringRef new_name, Status &error); + + void RemoveName(const char *name_to_remove) { + if (name_to_remove) + m_name_list.erase(name_to_remove); + } + + bool MatchesName(const char *name) { + return m_name_list.find(name) != m_name_list.end(); + } + + void GetNames(std::vector &names) { + names.clear(); + for (auto name : m_name_list) { + names.push_back(name); + } + } + + //------------------------------------------------------------------ + /// Set a pre-condition filter that overrides all user provided + /// filters/callbacks etc. + /// + /// Used to define fancy breakpoints that can do dynamic hit detection without + /// taking up the condition slot - + /// which really belongs to the user anyway... + /// + /// The Precondition should not continue the target, it should return true if + /// the condition says to stop and + /// false otherwise. + /// + //------------------------------------------------------------------ + void SetPrecondition(BreakpointPreconditionSP precondition_sp) { + m_precondition_sp = precondition_sp; + } + + bool EvaluatePrecondition(StoppointCallbackContext &context); + + BreakpointPreconditionSP GetPrecondition() { return m_precondition_sp; } + +protected: + friend class Target; + //------------------------------------------------------------------ + // Protected Methods + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Constructors and Destructors + /// Only the Target can make a breakpoint, and it owns the breakpoint + /// lifespans. + /// The constructor takes a filter and a resolver. Up in Target there are + /// convenience + /// variants that make breakpoints for some common cases. + /// + /// @param[in] target + /// The target in which the breakpoint will be set. + /// + /// @param[in] filter_sp + /// Shared pointer to the search filter that restricts the search domain of + /// the breakpoint. + /// + /// @param[in] resolver_sp + /// Shared pointer to the resolver object that will determine breakpoint + /// matches. + /// + /// @param hardware + /// If true, request a hardware breakpoint to be used to implement the + /// breakpoint locations. + /// + /// @param resolve_indirect_symbols + /// If true, and the address of a given breakpoint location in this + /// breakpoint is set on an + /// indirect symbol (i.e. Symbol::IsIndirect returns true) then the actual + /// breakpoint site will + /// be set on the target of the indirect symbol. + //------------------------------------------------------------------ + // This is the generic constructor + Breakpoint(Target &target, lldb::SearchFilterSP &filter_sp, + lldb::BreakpointResolverSP &resolver_sp, bool hardware, + bool resolve_indirect_symbols = true); + + friend class BreakpointLocation; // To call the following two when determining + // whether to stop. + + void DecrementIgnoreCount(); + + // BreakpointLocation::IgnoreCountShouldStop & + // Breakpoint::IgnoreCountShouldStop can only be called once per stop, + // and BreakpointLocation::IgnoreCountShouldStop should be tested first, and + // if it returns false we should + // continue, otherwise we should test Breakpoint::IgnoreCountShouldStop. + + bool IgnoreCountShouldStop(); + + void IncrementHitCount() { m_hit_count++; } + + void DecrementHitCount() { + assert(m_hit_count > 0); + m_hit_count--; + } + +private: + // This one should only be used by Target to copy breakpoints from target to + // target - primarily from the dummy + // target to prime new targets. + Breakpoint(Target &new_target, Breakpoint &bp_to_copy_from); + + //------------------------------------------------------------------ + // For Breakpoint only + //------------------------------------------------------------------ + bool m_being_created; + bool + m_hardware; // If this breakpoint is required to use a hardware breakpoint + Target &m_target; // The target that holds this breakpoint. + std::unordered_set m_name_list; // If not empty, this is the name + // of this breakpoint (many + // breakpoints can share the same + // name.) + lldb::SearchFilterSP + m_filter_sp; // The filter that constrains the breakpoint's domain. + lldb::BreakpointResolverSP + m_resolver_sp; // The resolver that defines this breakpoint. + BreakpointPreconditionSP m_precondition_sp; // The precondition is a + // breakpoint-level hit filter + // that can be used + // to skip certain breakpoint hits. For instance, exception breakpoints + // use this to limit the stop to certain exception classes, while leaving + // the condition & callback free for user specification. + std::unique_ptr + m_options_up; // Settable breakpoint options + BreakpointLocationList + m_locations; // The list of locations currently found for this breakpoint. + std::string m_kind_description; + bool m_resolve_indirect_symbols; + uint32_t m_hit_count; // Number of times this breakpoint/watchpoint has been + // hit. This is kept + // separately from the locations hit counts, since locations can go away when + // their backing library gets unloaded, and we would lose hit counts. + + void SendBreakpointChangedEvent(lldb::BreakpointEventType eventKind); + + void SendBreakpointChangedEvent(BreakpointEventData *data); + + DISALLOW_COPY_AND_ASSIGN(Breakpoint); +}; + +} // namespace lldb_private + +#endif // liblldb_Breakpoint_h_ diff --git a/include/lldb/Breakpoint/BreakpointID.h b/include/lldb/Breakpoint/BreakpointID.h new file mode 100644 index 000000000..57411b316 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointID.h @@ -0,0 +1,111 @@ +//===-- 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" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.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() const { return m_break_id; } + + lldb::break_id_t GetLocationID() const { 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(llvm::StringRef str); + static bool IsValidIDExpression(llvm::StringRef str); + static llvm::ArrayRef GetRangeSpecifiers(); + + //------------------------------------------------------------------ + /// Takes an input string containing the description of a breakpoint or + /// breakpoint and location and returns the a BreakpointID filled out with + /// the proper id and location. + /// + /// @param[in] input + /// A string containing JUST the breakpoint description. + /// @return + /// If \p input was not a valid breakpoint ID string, returns + /// \b llvm::None. Otherwise returns a BreakpointID with members filled + /// out accordingly. + //------------------------------------------------------------------ + static llvm::Optional + ParseCanonicalReference(llvm::StringRef input); + + //------------------------------------------------------------------ + /// Takes an input string and checks to see whether it is a breakpoint name. + /// If it is a mal-formed breakpoint name, error will be set to an appropriate + /// error string. + /// + /// @param[in] input + /// A string containing JUST the breakpoint description. + /// @param[out] error + /// If the name is a well-formed breakpoint name, set to success, + /// otherwise set to an error. + /// @return + /// \b true if the name is a breakpoint name (as opposed to an ID or + /// range) false otherwise. + //------------------------------------------------------------------ + static bool StringIsBreakpointName(llvm::StringRef str, Status &error); + + //------------------------------------------------------------------ + /// Takes a breakpoint ID and the breakpoint location id and returns + /// a string containing the canonical description for the breakpoint + /// or breakpoint location. + /// + /// @param[out] break_id + /// This is the break id. + /// + /// @param[out] break_loc_id + /// This is breakpoint location id, or LLDB_INVALID_BREAK_ID is no + /// location is to be specified. + //------------------------------------------------------------------ + static void GetCanonicalReference(Stream *s, lldb::break_id_t break_id, + lldb::break_id_t break_loc_id); + +protected: + lldb::break_id_t m_break_id; + lldb::break_id_t m_location_id; +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointID_h_ diff --git a/include/lldb/Breakpoint/BreakpointIDList.h b/include/lldb/Breakpoint/BreakpointIDList.h new file mode 100644 index 000000000..34cfbfe32 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointIDList.h @@ -0,0 +1,79 @@ +//===-- 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 +#include + +// Other libraries and framework includes +// Project includes + +#include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +// class BreakpointIDList +//---------------------------------------------------------------------- + +class BreakpointIDList { +public: + // TODO: Convert this class to StringRef. + typedef std::vector BreakpointIDArray; + + BreakpointIDList(); + + virtual ~BreakpointIDList(); + + size_t GetSize() const; + + const BreakpointID &GetBreakpointIDAtIndex(size_t index) const; + + bool RemoveBreakpointIDAtIndex(size_t index); + + void Clear(); + + bool AddBreakpointID(BreakpointID bp_id); + + bool AddBreakpointID(const char *bp_id); + + // TODO: This should take a const BreakpointID. + bool FindBreakpointID(BreakpointID &bp_id, size_t *position) const; + + bool FindBreakpointID(const char *bp_id, size_t *position) const; + + void InsertStringArray(const char **string_array, size_t array_size, + CommandReturnObject &result); + + // Returns a pair consisting of the beginning and end of a breakpoint + // ID range expression. If the input string is not a valid specification, + // returns an empty pair. + static std::pair + SplitIDRangeExpression(llvm::StringRef in_string); + + static void FindAndReplaceIDRanges(Args &old_args, Target *target, + bool allow_locations, + CommandReturnObject &result, + Args &new_args); + +private: + BreakpointIDArray m_breakpoint_ids; + BreakpointID m_invalid_id; + + DISALLOW_COPY_AND_ASSIGN(BreakpointIDList); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointIDList_h_ diff --git a/include/lldb/Breakpoint/BreakpointList.h b/include/lldb/Breakpoint/BreakpointList.h new file mode 100644 index 000000000..2865288ac --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointList.h @@ -0,0 +1,222 @@ +//===-- 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 +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/Breakpoint.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class BreakpointList BreakpointList.h "lldb/Breakpoint/BreakpointList.h" +/// @brief This class manages a list of breakpoints. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +/// General Outline: +/// Allows adding and removing breakpoints and find by ID and index. +//---------------------------------------------------------------------- + +class BreakpointList { +public: + BreakpointList(bool is_internal); + + ~BreakpointList(); + + //------------------------------------------------------------------ + /// Add the breakpoint \a bp_sp to the list. + /// + /// @param[in] bp_sp + /// Shared pointer to the breakpoint that will get added to the list. + /// + /// @result + /// Returns breakpoint id. + //------------------------------------------------------------------ + lldb::break_id_t Add(lldb::BreakpointSP &bp_sp, bool notify); + + //------------------------------------------------------------------ + /// Standard "Dump" method. At present it does nothing. + //------------------------------------------------------------------ + void Dump(Stream *s) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint with id \a breakID. + /// + /// @param[in] breakID + /// The breakpoint ID to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL pointer if the + /// breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointSP FindBreakpointByID(lldb::break_id_t breakID); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint with id \a breakID. Const + /// version. + /// + /// @param[in] breakID + /// The breakpoint ID to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL pointer if the + /// breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointSP FindBreakpointByID(lldb::break_id_t breakID) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint with index \a i. + /// + /// @param[in] i + /// The breakpoint index to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL pointer if the + /// breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointSP GetBreakpointAtIndex(size_t i); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint with index \a i, const version + /// + /// @param[in] i + /// The breakpoint index to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL pointer if the + /// breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointSP GetBreakpointAtIndex(size_t i) const; + + //------------------------------------------------------------------ + /// Find all the breakpoints with a given name + /// + /// @param[in] name + /// The breakpoint name for which to search. + /// + /// @result + /// \bfalse if the input name was not a legal breakpoint name. + //------------------------------------------------------------------ + bool FindBreakpointsByName(const char *name, BreakpointList &matching_bps); + + //------------------------------------------------------------------ + /// Returns the number of elements in this breakpoint list. + /// + /// @result + /// The number of elements. + //------------------------------------------------------------------ + size_t GetSize() const { + std::lock_guard guard(m_mutex); + return m_breakpoints.size(); + } + + //------------------------------------------------------------------ + /// Removes the breakpoint given by \b breakID from this list. + /// + /// @param[in] breakID + /// The breakpoint index to remove. + /// + /// @result + /// \b true if the breakpoint \a breakID was in the list. + //------------------------------------------------------------------ + bool Remove(lldb::break_id_t breakID, bool notify); + + //------------------------------------------------------------------ + /// Removes all invalid breakpoint locations. + /// + /// Removes all breakpoint locations in the list with architectures + /// that aren't compatible with \a arch. Also remove any breakpoint + /// locations with whose locations have address where the section + /// has been deleted (module and object files no longer exist). + /// + /// This is typically used after the process calls exec, or anytime + /// the architecture of the target changes. + /// + /// @param[in] arch + /// If valid, check the module in each breakpoint to make sure + /// they are compatible, otherwise, ignore architecture. + //------------------------------------------------------------------ + void RemoveInvalidLocations(const ArchSpec &arch); + + void SetEnabledAll(bool enabled); + + //------------------------------------------------------------------ + /// Removes all the breakpoints from this list. + //------------------------------------------------------------------ + void RemoveAll(bool notify); + + //------------------------------------------------------------------ + /// Tell all the breakpoints to update themselves due to a change in the + /// modules in \a module_list. \a added says whether the module was loaded + /// or unloaded. + /// + /// @param[in] module_list + /// The module list that has changed. + /// + /// @param[in] load + /// \b true if the modules are loaded, \b false if unloaded. + /// + /// @param[in] delete_locations + /// If \a load is \b false, then delete breakpoint locations when + /// when updating breakpoints. + //------------------------------------------------------------------ + void UpdateBreakpoints(ModuleList &module_list, bool load, + bool delete_locations); + + void UpdateBreakpointsWhenModuleIsReplaced(lldb::ModuleSP old_module_sp, + lldb::ModuleSP new_module_sp); + + void ClearAllBreakpointSites(); + + //------------------------------------------------------------------ + /// Sets the passed in Locker to hold the Breakpoint List mutex. + /// + /// @param[in] locker + /// The locker object that is set. + //------------------------------------------------------------------ + void GetListMutex(std::unique_lock &lock); + +protected: + typedef std::list bp_collection; + + bp_collection::iterator GetBreakpointIDIterator(lldb::break_id_t breakID); + + bp_collection::const_iterator + GetBreakpointIDConstIterator(lldb::break_id_t breakID) const; + + std::recursive_mutex &GetMutex() const { return m_mutex; } + + mutable std::recursive_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; + +public: + typedef LockingAdaptedIterable + BreakpointIterable; + BreakpointIterable Breakpoints() { + return BreakpointIterable(m_breakpoints, GetMutex()); + } + +private: + DISALLOW_COPY_AND_ASSIGN(BreakpointList); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointList_h_ diff --git a/include/lldb/Breakpoint/BreakpointLocation.h b/include/lldb/Breakpoint/BreakpointLocation.h new file mode 100644 index 000000000..a1086aa3f --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointLocation.h @@ -0,0 +1,429 @@ +//===-- 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 +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/StoppointLocation.h" +#include "lldb/Core/Address.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class BreakpointLocation BreakpointLocation.h +/// "lldb/Breakpoint/BreakpointLocation.h" +/// @brief Class that manages one unique (by address) instance of a logical +/// breakpoint. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +/// General Outline: +/// A breakpoint location is defined by the breakpoint that produces it, +/// and the address that resulted in this particular instantiation. +/// Each breakpoint location also may have a breakpoint site if its +/// address has been loaded into the program. +/// Finally it has a settable options object. +/// +/// FIXME: Should we also store some fingerprint for the location, so +/// we can map one location to the "equivalent location" on rerun? This +/// would be useful if you've set options on the locations. +//---------------------------------------------------------------------- + +class BreakpointLocation + : public std::enable_shared_from_this, + public StoppointLocation { +public: + ~BreakpointLocation() override; + + //------------------------------------------------------------------ + /// Gets the load address for this breakpoint location + /// @return + /// Returns breakpoint location load address, \b + /// LLDB_INVALID_ADDRESS if not yet set. + //------------------------------------------------------------------ + lldb::addr_t GetLoadAddress() const override; + + //------------------------------------------------------------------ + /// 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(); + + Target &GetTarget(); + + //------------------------------------------------------------------ + /// 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) override; + + //------------------------------------------------------------------ + // The next section deals with various breakpoint options. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// If \a enable is \b true, enable the breakpoint, if \b false + /// disable it. + //------------------------------------------------------------------ + void SetEnabled(bool enabled); + + //------------------------------------------------------------------ + /// Check the Enable/Disable state. + /// + /// @return + /// \b true if the breakpoint is enabled, \b false if disabled. + //------------------------------------------------------------------ + bool IsEnabled() const; + + //------------------------------------------------------------------ + /// Return the current Ignore Count. + /// + /// @return + /// The number of breakpoint hits to be ignored. + //------------------------------------------------------------------ + uint32_t GetIgnoreCount(); + + //------------------------------------------------------------------ + /// Set the breakpoint to ignore the next \a count breakpoint hits. + /// + /// @param[in] count + /// The number of breakpoint hits to ignore. + //------------------------------------------------------------------ + void SetIgnoreCount(uint32_t n); + + //------------------------------------------------------------------ + /// Set the callback action invoked when the breakpoint is hit. + /// + /// The callback will return a bool indicating whether the target + /// should stop at this breakpoint or not. + /// + /// @param[in] callback + /// The method that will get called when the breakpoint is hit. + /// + /// @param[in] callback_baton_sp + /// A shared pointer to a Baton that provides the void * needed + /// for the callback. + /// + /// @see lldb_private::Baton + //------------------------------------------------------------------ + void SetCallback(BreakpointHitCallback callback, + const lldb::BatonSP &callback_baton_sp, bool is_synchronous); + + void SetCallback(BreakpointHitCallback callback, void *baton, + bool is_synchronous); + + void ClearCallback(); + + //------------------------------------------------------------------ + /// Set the breakpoint location's condition. + /// + /// @param[in] condition + /// The condition expression to evaluate when the breakpoint is hit. + //------------------------------------------------------------------ + void SetCondition(const char *condition); + + //------------------------------------------------------------------ + /// Return a pointer to the text of the condition expression. + /// + /// @return + /// A pointer to the condition expression text, or nullptr if no + // condition has been set. + //------------------------------------------------------------------ + const char *GetConditionText(size_t *hash = nullptr) const; + + bool ConditionSaysStop(ExecutionContext &exe_ctx, Status &error); + + //------------------------------------------------------------------ + /// Set the valid thread to be checked when the breakpoint is hit. + /// + /// @param[in] thread_id + /// If this thread hits the breakpoint, we stop, otherwise not. + //------------------------------------------------------------------ + void SetThreadID(lldb::tid_t thread_id); + + lldb::tid_t GetThreadID(); + + void SetThreadIndex(uint32_t index); + + uint32_t GetThreadIndex() const; + + void SetThreadName(const char *thread_name); + + const char *GetThreadName() const; + + void SetQueueName(const char *queue_name); + + const char *GetQueueName() const; + + //------------------------------------------------------------------ + // The next section deals with this location's breakpoint sites. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Try to resolve the breakpoint site for this location. + /// + /// @return + /// \b true if we were successful at setting a breakpoint site, + /// \b false otherwise. + //------------------------------------------------------------------ + bool ResolveBreakpointSite(); + + //------------------------------------------------------------------ + /// Clear this breakpoint location's breakpoint site - for instance + /// when disabling the breakpoint. + /// + /// @return + /// \b true if there was a breakpoint site to be cleared, \b false + /// otherwise. + //------------------------------------------------------------------ + bool ClearBreakpointSite(); + + //------------------------------------------------------------------ + /// Return whether this breakpoint location has a breakpoint site. + /// @return + /// \b true if there was a breakpoint site for this breakpoint + /// location, \b false otherwise. + //------------------------------------------------------------------ + bool IsResolved() const; + + lldb::BreakpointSiteSP GetBreakpointSite() const; + + //------------------------------------------------------------------ + // The next section are generic report functions. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Print a description of this breakpoint location to the stream + /// \a s. + /// + /// @param[in] s + /// The stream to which to print the description. + /// + /// @param[in] level + /// The description level that indicates the detail level to + /// provide. + /// + /// @see lldb::DescriptionLevel + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level); + + //------------------------------------------------------------------ + /// Standard "Dump" method. At present it does nothing. + //------------------------------------------------------------------ + void Dump(Stream *s) const override; + + //------------------------------------------------------------------ + /// Use this to set location specific breakpoint options. + /// + /// It will create a copy of the containing breakpoint's options if + /// that hasn't been done already + /// + /// @return + /// A pointer to the breakpoint options. + //------------------------------------------------------------------ + BreakpointOptions *GetLocationOptions(); + + //------------------------------------------------------------------ + /// Use this to access breakpoint options from this breakpoint location. + /// This will point to the owning breakpoint's options unless options have + /// been set specifically on this location. + /// + /// @return + /// A pointer to the containing breakpoint's options if this + /// location doesn't have its own copy. + //------------------------------------------------------------------ + const BreakpointOptions *GetOptionsNoCreate() const; + + bool ValidForThisThread(Thread *thread); + + //------------------------------------------------------------------ + /// Invoke the callback action when the breakpoint is hit. + /// + /// Meant to be used by the BreakpointLocation class. + /// + /// @param[in] context + /// Described the breakpoint event. + /// + /// @param[in] bp_loc_id + /// Which breakpoint location hit this breakpoint. + /// + /// @return + /// \b true if the target should stop at this breakpoint and \b + /// false not. + //------------------------------------------------------------------ + bool InvokeCallback(StoppointCallbackContext *context); + + //------------------------------------------------------------------ + /// Returns whether we should resolve Indirect functions in setting the + /// breakpoint site + /// for this location. + /// + /// @return + /// \b true if the breakpoint SITE for this location should be set on the + /// resolved location for Indirect functions. + //------------------------------------------------------------------ + bool ShouldResolveIndirectFunctions() { + return m_should_resolve_indirect_functions; + } + + //------------------------------------------------------------------ + /// Returns whether the address set in the breakpoint site for this location + /// was found by resolving + /// an indirect symbol. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool IsIndirect() { return m_is_indirect; } + + void SetIsIndirect(bool is_indirect) { m_is_indirect = is_indirect; } + + //------------------------------------------------------------------ + /// Returns whether the address set in the breakpoint location was re-routed + /// to the target of a + /// re-exported symbol. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool IsReExported() { return m_is_reexported; } + + void SetIsReExported(bool is_reexported) { m_is_reexported = is_reexported; } + + //------------------------------------------------------------------ + /// Returns whether the two breakpoint locations might represent "equivalent + /// locations". + /// This is used when modules changed to determine if a Location in the old + /// module might + /// be the "same as" the input location. + /// + /// @param[in] location + /// The location to compare against. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool EquivalentToLocation(BreakpointLocation &location); + +protected: + friend class BreakpointSite; + friend class BreakpointLocationList; + friend class Process; + friend class StopInfoBreakpoint; + + //------------------------------------------------------------------ + /// Set the breakpoint site for this location to \a bp_site_sp. + /// + /// @param[in] bp_site_sp + /// The breakpoint site we are setting for this location. + /// + /// @return + /// \b true if we were successful at setting the breakpoint site, + /// \b false otherwise. + //------------------------------------------------------------------ + bool SetBreakpointSite(lldb::BreakpointSiteSP &bp_site_sp); + + void DecrementIgnoreCount(); + + bool IgnoreCountShouldStop(); + +private: + void SwapLocation(lldb::BreakpointLocationSP swap_from); + + void BumpHitCount(); + + void UndoBumpHitCount(); + + //------------------------------------------------------------------ + // Constructors and Destructors + // + // Only the Breakpoint can make breakpoint locations, and it owns + // them. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Constructor. + /// + /// @param[in] owner + /// A back pointer to the breakpoint that owns this location. + /// + /// @param[in] addr + /// The Address defining this location. + /// + /// @param[in] tid + /// The thread for which this breakpoint location is valid, or + /// LLDB_INVALID_THREAD_ID if it is valid for all threads. + /// + /// @param[in] hardware + /// \b true if a hardware breakpoint is requested. + //------------------------------------------------------------------ + + BreakpointLocation(lldb::break_id_t bid, Breakpoint &owner, + const Address &addr, lldb::tid_t tid, bool hardware, + bool check_for_resolver = true); + + //------------------------------------------------------------------ + // Data members: + //------------------------------------------------------------------ + bool m_being_created; + bool m_should_resolve_indirect_functions; + bool m_is_reexported; + bool m_is_indirect; + Address m_address; ///< The address defining this location. + Breakpoint &m_owner; ///< The breakpoint that produced this object. + std::unique_ptr m_options_ap; ///< Breakpoint options + ///pointer, nullptr 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.) + lldb::UserExpressionSP m_user_expression_sp; ///< The compiled expression to + ///use in testing our condition. + std::mutex m_condition_mutex; ///< Guards parsing and evaluation of the + ///condition, which could be evaluated by + /// multiple processes. + size_t m_condition_hash; ///< For testing whether the condition source code + ///changed. + + void SetShouldResolveIndirectFunctions(bool do_resolve) { + m_should_resolve_indirect_functions = do_resolve; + } + + void SendBreakpointLocationChangedEvent(lldb::BreakpointEventType eventKind); + + DISALLOW_COPY_AND_ASSIGN(BreakpointLocation); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointLocation_h_ diff --git a/include/lldb/Breakpoint/BreakpointLocationCollection.h b/include/lldb/Breakpoint/BreakpointLocationCollection.h new file mode 100644 index 000000000..4b2d9d4b3 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointLocationCollection.h @@ -0,0 +1,213 @@ +//===-- 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 +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Iterable.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class BreakpointLocationCollection { +public: + BreakpointLocationCollection(); + + ~BreakpointLocationCollection(); + + //------------------------------------------------------------------ + /// Add the breakpoint \a bp_loc_sp to the list. + /// + /// @param[in] bp_sp + /// Shared pointer to the breakpoint location that will get added + /// to the list. + /// + /// @result + /// Returns breakpoint location id. + //------------------------------------------------------------------ + void Add(const lldb::BreakpointLocationSP &bp_loc_sp); + + //------------------------------------------------------------------ + /// Removes the breakpoint location given by \b breakID from this + /// list. + /// + /// @param[in] break_id + /// The breakpoint index to remove. + /// + /// @param[in] break_loc_id + /// The breakpoint location index in break_id to remove. + /// + /// @result + /// \b true if the breakpoint was in the list. + //------------------------------------------------------------------ + bool Remove(lldb::break_id_t break_id, lldb::break_id_t break_loc_id); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with id \a + /// breakID. + /// + /// @param[in] break_id + /// The breakpoint ID to seek for. + /// + /// @param[in] break_loc_id + /// The breakpoint location ID in \a break_id to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP FindByIDPair(lldb::break_id_t break_id, + lldb::break_id_t break_loc_id); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with id \a + /// breakID, const version. + /// + /// @param[in] breakID + /// The breakpoint location ID to seek for. + /// + /// @param[in] break_loc_id + /// The breakpoint location ID in \a break_id to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointLocationSP + FindByIDPair(lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with index + /// \a i. + /// + /// @param[in] i + /// The breakpoint location index to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP GetByIndex(size_t i); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with index + /// \a i, const version. + /// + /// @param[in] i + /// The breakpoint location index to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a NULL + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointLocationSP GetByIndex(size_t i) const; + + //------------------------------------------------------------------ + /// Returns the number of elements in this breakpoint location list. + /// + /// @result + /// The number of elements. + //------------------------------------------------------------------ + size_t GetSize() const { return m_break_loc_collection.size(); } + + //------------------------------------------------------------------ + /// Enquires of all the breakpoint locations in this list whether + /// we should stop at a hit at \a breakID. + /// + /// @param[in] context + /// This contains the information about this stop. + /// + /// @param[in] breakID + /// This break ID that we hit. + /// + /// @return + /// \b true if we should stop, \b false otherwise. + //------------------------------------------------------------------ + bool ShouldStop(StoppointCallbackContext *context); + + //------------------------------------------------------------------ + /// Print a description of the breakpoint locations in this list + /// to the stream \a s. + /// + /// @param[in] s + /// The stream to which to print the description. + /// + /// @param[in] level + /// The description level that indicates the detail level to + /// provide. + /// + /// @see lldb::DescriptionLevel + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level); + + //------------------------------------------------------------------ + /// Check whether this collection of breakpoint locations have any + /// thread specifiers, and if yes, is \a thread_id contained in any + /// of these specifiers. + /// + /// @param[in] thread + /// The thread against which to test. + /// + /// return + /// \b true if the collection contains at least one location that + /// would be valid for this thread, false otherwise. + //------------------------------------------------------------------ + bool ValidForThisThread(Thread *thread); + + //------------------------------------------------------------------ + /// Tell whether ALL the breakpoints in the location collection are internal. + /// + /// @result + /// \b true if all breakpoint locations are owned by internal breakpoints, + /// \b false otherwise. + //------------------------------------------------------------------ + bool IsInternal() const; + +protected: + //------------------------------------------------------------------ + // Classes that inherit from BreakpointLocationCollection can see + // and modify these + //------------------------------------------------------------------ + +private: + //------------------------------------------------------------------ + // For BreakpointLocationCollection only + //------------------------------------------------------------------ + + typedef std::vector collection; + + collection::iterator GetIDPairIterator(lldb::break_id_t break_id, + lldb::break_id_t break_loc_id); + + collection::const_iterator + GetIDPairConstIterator(lldb::break_id_t break_id, + lldb::break_id_t break_loc_id) const; + + collection m_break_loc_collection; + mutable std::mutex m_collection_mutex; + +public: + typedef AdaptedIterable + BreakpointLocationCollectionIterable; + BreakpointLocationCollectionIterable BreakpointLocations() { + return BreakpointLocationCollectionIterable(m_break_loc_collection); + } +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointLocationCollection_h_ diff --git a/include/lldb/Breakpoint/BreakpointLocationList.h b/include/lldb/Breakpoint/BreakpointLocationList.h new file mode 100644 index 000000000..46eb2612b --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointLocationList.h @@ -0,0 +1,267 @@ +//===-- 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 +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Address.h" +#include "lldb/Utility/Iterable.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class BreakpointLocationList BreakpointLocationList.h +/// "lldb/Breakpoint/BreakpointLocationList.h" +/// @brief This class is used by Breakpoint to manage a list of breakpoint +/// locations, +// each breakpoint location in the list +/// has a unique ID, and is unique by Address as well. +//---------------------------------------------------------------------- + +class BreakpointLocationList { + // Only Breakpoints can make the location list, or add elements to it. + // This is not just some random collection of locations. Rather, the act of + // adding the location + // to this list sets its ID, and implicitly all the locations have the same + // breakpoint ID as + // well. If you need a generic container for breakpoint locations, use + // BreakpointLocationCollection. + friend class Breakpoint; + +public: + virtual ~BreakpointLocationList(); + + //------------------------------------------------------------------ + /// Standard "Dump" method. At present it does nothing. + //------------------------------------------------------------------ + void Dump(Stream *s) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location at address + /// \a addr - const version. + /// + /// @param[in] addr + /// The address to look for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a nullptr + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointLocationSP FindByAddress(const Address &addr) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with id + /// \a breakID, const version. + /// + /// @param[in] breakID + /// The breakpoint location ID to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a nullptr + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP FindByID(lldb::break_id_t breakID) const; + + //------------------------------------------------------------------ + /// Returns the breakpoint location id to the breakpoint location + /// at address \a addr. + /// + /// @param[in] addr + /// The address to match. + /// + /// @result + /// The ID of the breakpoint location, or LLDB_INVALID_BREAK_ID. + //------------------------------------------------------------------ + lldb::break_id_t FindIDByAddress(const Address &addr); + + //------------------------------------------------------------------ + /// Returns a breakpoint location list of the breakpoint locations + /// in the module \a module. This list is allocated, and owned by + /// the caller. + /// + /// @param[in] module + /// The module to seek in. + /// + /// @param[in] + /// A breakpoint collection that gets any breakpoint locations + /// that match \a module appended to. + /// + /// @result + /// The number of matches + //------------------------------------------------------------------ + size_t FindInModule(Module *module, + BreakpointLocationCollection &bp_loc_list); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with + /// index \a i. + /// + /// @param[in] i + /// The breakpoint location index to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a nullptr + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP GetByIndex(size_t i); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint location with index + /// \a i, const version. + /// + /// @param[in] i + /// The breakpoint location index to seek for. + /// + /// @result + /// A shared pointer to the breakpoint. May contain a nullptr + /// pointer if the breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointLocationSP GetByIndex(size_t i) const; + + //------------------------------------------------------------------ + /// Removes all the locations in this list from their breakpoint site + /// owners list. + //------------------------------------------------------------------ + void ClearAllBreakpointSites(); + + //------------------------------------------------------------------ + /// Tells all the breakpoint locations in this list to attempt to + /// resolve any possible breakpoint sites. + //------------------------------------------------------------------ + void ResolveAllBreakpointSites(); + + //------------------------------------------------------------------ + /// Returns the number of breakpoint locations in this list with + /// resolved breakpoints. + /// + /// @result + /// Number of qualifying breakpoint locations. + //------------------------------------------------------------------ + size_t GetNumResolvedLocations() const; + + //------------------------------------------------------------------ + /// Returns the number hit count of all locations in this list. + /// + /// @result + /// Hit count of all locations in this list. + //------------------------------------------------------------------ + uint32_t GetHitCount() const; + + //------------------------------------------------------------------ + /// Enquires of the breakpoint location in this list with ID \a + /// breakID whether we should stop. + /// + /// @param[in] context + /// This contains the information about this stop. + /// + /// @param[in] breakID + /// This break ID that we hit. + /// + /// @return + /// \b true if we should stop, \b false otherwise. + //------------------------------------------------------------------ + bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID); + + //------------------------------------------------------------------ + /// Returns the number of elements in this breakpoint location list. + /// + /// @result + /// The number of elements. + //------------------------------------------------------------------ + size_t GetSize() const { return m_locations.size(); } + + //------------------------------------------------------------------ + /// Print a description of the breakpoint locations in this list to + /// the stream \a s. + /// + /// @param[in] s + /// The stream to which to print the description. + /// + /// @param[in] level + /// The description level that indicates the detail level to + /// provide. + /// + /// @see lldb::DescriptionLevel + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level); + +protected: + //------------------------------------------------------------------ + /// This is the standard constructor. + /// + /// It creates an empty breakpoint location list. It is protected + /// here because only Breakpoints are allowed to create the + /// breakpoint location list. + //------------------------------------------------------------------ + BreakpointLocationList(Breakpoint &owner); + + //------------------------------------------------------------------ + /// Add the breakpoint \a bp_loc_sp to the list. + /// + /// @param[in] bp_sp + /// Shared pointer to the breakpoint location that will get + /// added to the list. + /// + /// @result + /// Returns breakpoint location id. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP Create(const Address &addr, + bool resolve_indirect_symbols); + + void StartRecordingNewLocations(BreakpointLocationCollection &new_locations); + + void StopRecordingNewLocations(); + + lldb::BreakpointLocationSP AddLocation(const Address &addr, + bool resolve_indirect_symbols, + bool *new_location = nullptr); + + void SwapLocation(lldb::BreakpointLocationSP to_location_sp, + lldb::BreakpointLocationSP from_location_sp); + + bool RemoveLocation(const lldb::BreakpointLocationSP &bp_loc_sp); + + void RemoveInvalidLocations(const ArchSpec &arch); + + void Compact(); + + typedef std::vector collection; + typedef std::map + addr_map; + + Breakpoint &m_owner; + collection m_locations; // Vector of locations, sorted by ID + addr_map m_address_to_location; + mutable std::recursive_mutex m_mutex; + lldb::break_id_t m_next_id; + BreakpointLocationCollection *m_new_location_recorder; + +public: + typedef AdaptedIterable + BreakpointLocationIterable; + + BreakpointLocationIterable BreakpointLocations() { + return BreakpointLocationIterable(m_locations); + } +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointLocationList_h_ diff --git a/include/lldb/Breakpoint/BreakpointOptions.h b/include/lldb/Breakpoint/BreakpointOptions.h new file mode 100644 index 000000000..420d5915f --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointOptions.h @@ -0,0 +1,407 @@ +//===-- 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 +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Baton.h" +#include "lldb/Utility/StringList.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-private.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: + struct CommandData { + CommandData() + : user_source(), script_source(), + interpreter(lldb::eScriptLanguageNone), stop_on_error(true) {} + + CommandData(const StringList &user_source, lldb::ScriptLanguage interp) + : user_source(user_source), script_source(), interpreter(interp), + stop_on_error(true) {} + + ~CommandData() = default; + + static const char *GetSerializationKey() { return "BKPTCMDData"; } + + StructuredData::ObjectSP SerializeToStructuredData(); + + static std::unique_ptr + CreateFromStructuredData(const StructuredData::Dictionary &options_dict, + Status &error); + + StringList user_source; + std::string script_source; + enum lldb::ScriptLanguage + interpreter; // eScriptLanguageNone means command interpreter. + bool stop_on_error; + + private: + enum class OptionNames : uint32_t { + UserSource = 0, + Interpreter, + StopOnError, + LastOptionName + }; + + static const char + *g_option_names[static_cast(OptionNames::LastOptionName)]; + + static const char *GetKey(OptionNames enum_value) { + return g_option_names[static_cast(enum_value)]; + } + }; + + class CommandBaton : public TypedBaton { + public: + explicit CommandBaton(std::unique_ptr Data) + : TypedBaton(std::move(Data)) {} + + void GetDescription(Stream *s, lldb::DescriptionLevel level) const override; + }; + + typedef std::shared_ptr CommandBatonSP; + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// Default constructor. The breakpoint is enabled, and has no condition, + /// callback, ignore count, etc... + //------------------------------------------------------------------ + BreakpointOptions(); + BreakpointOptions(const BreakpointOptions &rhs); + + static BreakpointOptions *CopyOptionsNoCallback(BreakpointOptions &rhs); + + //------------------------------------------------------------------ + /// This constructor allows you to specify all the breakpoint options + /// except the callback. That one is more complicated, and better + /// to do by hand. + /// + /// @param[in] condition + /// The expression which if it evaluates to \b true if we are to stop + /// + /// @param[in] enabled + /// Is this breakpoint enabled. + /// + /// @param[in] ignore + /// How many breakpoint hits we should ignore before stopping. + /// + //------------------------------------------------------------------ + BreakpointOptions(const char *condition, bool enabled = true, + int32_t ignore = 0, bool one_shot = false); + + virtual ~BreakpointOptions(); + + static std::unique_ptr + CreateFromStructuredData(Target &target, + const StructuredData::Dictionary &data_dict, + Status &error); + + virtual StructuredData::ObjectSP SerializeToStructuredData(); + + static const char *GetSerializationKey() { return "BKPTOptions"; } + + //------------------------------------------------------------------ + // Operators + //------------------------------------------------------------------ + const BreakpointOptions &operator=(const BreakpointOptions &rhs); + + //------------------------------------------------------------------ + // Callbacks + // + // Breakpoint callbacks come in two forms, synchronous and asynchronous. + // Synchronous callbacks will get + // run before any of the thread plans are consulted, and if they return false + // the target will continue + // "under the radar" of the thread plans. There are a couple of restrictions + // to synchronous callbacks: + // 1) They should NOT resume the target themselves. Just return false if you + // want the target to restart. + // 2) Breakpoints with synchronous callbacks can't have conditions (or rather, + // they can have them, but they + // won't do anything. Ditto with ignore counts, etc... You are supposed + // to control that all through the + // callback. + // Asynchronous callbacks get run as part of the "ShouldStop" logic in the + // thread plan. The logic there is: + // a) If the breakpoint is thread specific and not for this thread, continue + // w/o running the callback. + // NB. This is actually enforced underneath the breakpoint system, the + // Process plugin is expected to + // call BreakpointSite::IsValidForThread, and set the thread's StopInfo + // to "no reason". That way, + // thread displays won't show stops for breakpoints not for that + // thread... + // b) If the ignore count says we shouldn't stop, then ditto. + // c) If the condition says we shouldn't stop, then ditto. + // d) Otherwise, the callback will get run, and if it returns true we will + // stop, and if false we won't. + // The asynchronous callback can run the target itself, but at present that + // should be the last action the + // callback does. We will relax this condition at some point, but it will + // take a bit of plumbing to get + // that to work. + // + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Adds a callback to the breakpoint option set. + /// + /// @param[in] callback + /// The function to be called when the breakpoint gets hit. + /// + /// @param[in] baton_sp + /// A baton which will get passed back to the callback when it is invoked. + /// + /// @param[in] synchronous + /// Whether this is a synchronous or asynchronous callback. See discussion + /// above. + //------------------------------------------------------------------ + void SetCallback(BreakpointHitCallback callback, + const lldb::BatonSP &baton_sp, bool synchronous = false); + + void SetCallback(BreakpointHitCallback callback, + const BreakpointOptions::CommandBatonSP &command_baton_sp, + bool synchronous = false); + + //------------------------------------------------------------------ + /// Returns the command line commands for the callback on this breakpoint. + /// + /// @param[out] command_list + /// The commands will be appended to this list. + /// + /// @return + /// \btrue if the command callback is a command-line callback, + /// \bfalse otherwise. + //------------------------------------------------------------------ + bool GetCommandLineCallbacks(StringList &command_list); + + //------------------------------------------------------------------ + /// Remove the callback from this option set. + //------------------------------------------------------------------ + void ClearCallback(); + + // The rest of these functions are meant to be used only within the breakpoint + // handling mechanism. + + //------------------------------------------------------------------ + /// Use this function to invoke the callback for a specific stop. + /// + /// @param[in] context + /// The context in which the callback is to be invoked. This includes the + /// stop event, the + /// execution context of the stop (since you might hit the same breakpoint + /// on multiple threads) and + /// whether we are currently executing synchronous or asynchronous + /// callbacks. + /// + /// @param[in] break_id + /// The breakpoint ID that owns this option set. + /// + /// @param[in] break_loc_id + /// The breakpoint location ID that owns this option set. + /// + /// @return + /// The callback return value. + //------------------------------------------------------------------ + bool InvokeCallback(StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + //------------------------------------------------------------------ + /// Used in InvokeCallback to tell whether it is the right time to run this + /// kind of callback. + /// + /// @return + /// The synchronicity of our callback. + //------------------------------------------------------------------ + bool IsCallbackSynchronous() const { return m_callback_is_synchronous; } + + //------------------------------------------------------------------ + /// Fetch the baton from the callback. + /// + /// @return + /// The baton. + //------------------------------------------------------------------ + Baton *GetBaton(); + + //------------------------------------------------------------------ + /// Fetch a const version of the baton from the callback. + /// + /// @return + /// The baton. + //------------------------------------------------------------------ + const Baton *GetBaton() const; + + //------------------------------------------------------------------ + // Condition + //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// Set the breakpoint option's condition. + /// + /// @param[in] condition + /// The condition expression to evaluate when the breakpoint is hit. + //------------------------------------------------------------------ + void SetCondition(const char *condition); + + //------------------------------------------------------------------ + /// Return a pointer to the text of the condition expression. + /// + /// @return + /// A pointer to the condition expression text, or nullptr if no + // condition has been set. + //------------------------------------------------------------------ + const char *GetConditionText(size_t *hash = nullptr) const; + + //------------------------------------------------------------------ + // Enabled/Ignore Count + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Check the Enable/Disable state. + /// @return + /// \b true if the breakpoint is enabled, \b false if disabled. + //------------------------------------------------------------------ + bool IsEnabled() const { return m_enabled; } + + //------------------------------------------------------------------ + /// If \a enable is \b true, enable the breakpoint, if \b false disable it. + //------------------------------------------------------------------ + void SetEnabled(bool enabled) { m_enabled = enabled; } + + //------------------------------------------------------------------ + /// Check the One-shot state. + /// @return + /// \b true if the breakpoint is one-shot, \b false otherwise. + //------------------------------------------------------------------ + bool IsOneShot() const { return m_one_shot; } + + //------------------------------------------------------------------ + /// If \a enable is \b true, enable the breakpoint, if \b false disable it. + //------------------------------------------------------------------ + void SetOneShot(bool one_shot) { m_one_shot = one_shot; } + + //------------------------------------------------------------------ + /// Set the breakpoint to ignore the next \a count breakpoint hits. + /// @param[in] count + /// The number of breakpoint hits to ignore. + //------------------------------------------------------------------ + + void SetIgnoreCount(uint32_t n) { m_ignore_count = n; } + + //------------------------------------------------------------------ + /// Return the current Ignore Count. + /// @return + /// The number of breakpoint hits to be ignored. + //------------------------------------------------------------------ + uint32_t GetIgnoreCount() const { return m_ignore_count; } + + //------------------------------------------------------------------ + /// Return the current thread spec for this option. This will return nullptr + /// if the no thread + /// specifications have been set for this Option yet. + /// @return + /// The thread specification pointer for this option, or nullptr if none + /// has + /// been set yet. + //------------------------------------------------------------------ + const ThreadSpec *GetThreadSpecNoCreate() const; + + //------------------------------------------------------------------ + /// Returns a pointer to the ThreadSpec for this option, creating it. + /// if it hasn't been created already. This API is used for setting the + /// ThreadSpec items for this option. + //------------------------------------------------------------------ + ThreadSpec *GetThreadSpec(); + + void SetThreadID(lldb::tid_t thread_id); + + void GetDescription(Stream *s, lldb::DescriptionLevel level) const; + + //------------------------------------------------------------------ + /// Returns true if the breakpoint option has a callback set. + //------------------------------------------------------------------ + bool HasCallback() const; + + //------------------------------------------------------------------ + /// This is the default empty callback. + //------------------------------------------------------------------ + static bool NullCallback(void *baton, StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + //------------------------------------------------------------------ + /// Set a callback based on BreakpointOptions::CommandData. + /// @param[in] cmd_data + /// A UP holding the new'ed CommandData object. + /// The breakpoint will take ownership of pointer held by this object. + //------------------------------------------------------------------ + void SetCommandDataCallback(std::unique_ptr &cmd_data); + +protected: + //------------------------------------------------------------------ + // Classes that inherit from BreakpointOptions can see and modify these + //------------------------------------------------------------------ + enum class OptionNames { + ConditionText = 0, + IgnoreCount, + EnabledState, + OneShotState, + LastOptionName + }; + static const char *g_option_names[(size_t)OptionNames::LastOptionName]; + + static const char *GetKey(OptionNames enum_value) { + return g_option_names[(size_t)enum_value]; + } + + static bool BreakpointOptionsCallbackFunction( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + void SetThreadSpec(std::unique_ptr &thread_spec_up); + +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_baton_is_command_baton; + bool m_callback_is_synchronous; + bool m_enabled; + bool m_one_shot; + uint32_t m_ignore_count; // Number of times to ignore this breakpoint + std::unique_ptr + m_thread_spec_ap; // Thread for which this breakpoint will take + std::string m_condition_text; // The condition to test. + size_t m_condition_text_hash; // Its hash, so that locations know when the + // condition is updated. +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointOptions_h_ diff --git a/include/lldb/Breakpoint/BreakpointResolver.h b/include/lldb/Breakpoint/BreakpointResolver.h new file mode 100644 index 000000000..7bcd889ce --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointResolver.h @@ -0,0 +1,257 @@ +//===-- 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/Breakpoint/Breakpoint.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/SearchFilter.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/lldb-private.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 { + friend class Breakpoint; + +public: + //------------------------------------------------------------------ + /// The breakpoint resolver need to have a breakpoint for "ResolveBreakpoint + /// to make sense. It can be constructed without a breakpoint, but you have + /// to + /// call SetBreakpoint before ResolveBreakpoint. + /// + /// @param[in] bkpt + /// The breakpoint that owns this resolver. + /// @param[in] resolverType + /// The concrete breakpoint resolver type for this breakpoint. + /// + /// @result + /// Returns breakpoint location id. + //------------------------------------------------------------------ + BreakpointResolver(Breakpoint *bkpt, unsigned char resolverType, + lldb::addr_t offset = 0); + + //------------------------------------------------------------------ + /// The Destructor is virtual, all significant breakpoint resolvers derive + /// from this class. + //------------------------------------------------------------------ + ~BreakpointResolver() override; + + //------------------------------------------------------------------ + /// This sets the breakpoint for this resolver. + /// + /// @param[in] bkpt + /// The breakpoint that owns this resolver. + //------------------------------------------------------------------ + void SetBreakpoint(Breakpoint *bkpt); + + //------------------------------------------------------------------ + /// This updates the offset for this breakpoint. All the locations currently + /// set for this breakpoint will have their offset adjusted when this is + /// called. + /// + /// @param[in] offset + /// The offset to add to all locations. + //------------------------------------------------------------------ + void SetOffset(lldb::addr_t offset); + + //------------------------------------------------------------------ + /// This updates the offset for this breakpoint. All the locations currently + /// set for this breakpoint will have their offset adjusted when this is + /// called. + /// + /// @param[in] offset + /// The offset to add to all locations. + //------------------------------------------------------------------ + lldb::addr_t GetOffset() const { return m_offset; } + + //------------------------------------------------------------------ + /// 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. + //------------------------------------------------------------------ + void GetDescription(Stream *s) override = 0; + + //------------------------------------------------------------------ + /// Standard "Dump" method. At present it does nothing. + //------------------------------------------------------------------ + virtual void Dump(Stream *s) const = 0; + + /// This section handles serializing and deserializing from StructuredData + /// objects. + + static lldb::BreakpointResolverSP + CreateFromStructuredData(const StructuredData::Dictionary &resolver_dict, + Status &error); + + virtual StructuredData::ObjectSP SerializeToStructuredData() { + return StructuredData::ObjectSP(); + } + + static const char *GetSerializationKey() { return "BKPTResolver"; } + + static const char *GetSerializationSubclassKey() { return "Type"; } + + static const char *GetSerializationSubclassOptionsKey() { return "Options"; } + + StructuredData::DictionarySP + WrapOptionsDict(StructuredData::DictionarySP options_dict_sp); + + //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// An enumeration for keeping track of the concrete subclass that + /// is actually instantiated. Values of this enumeration are kept in the + /// BreakpointResolver's SubclassID field. They are used for concrete type + /// identification. + enum ResolverTy { + FileLineResolver = 0, // This is an instance of BreakpointResolverFileLine + AddressResolver, // This is an instance of BreakpointResolverAddress + NameResolver, // This is an instance of BreakpointResolverName + FileRegexResolver, + ExceptionResolver, + LastKnownResolverType = ExceptionResolver, + UnknownResolver + }; + + // Translate the Ty to name for serialization, + // the "+2" is one for size vrs. index, and one for UnknownResolver. + static const char *g_ty_to_name[LastKnownResolverType + 2]; + + //------------------------------------------------------------------ + /// getResolverID - Return an ID for the concrete type of this object. This + /// is used to implement the LLVM classof checks. This should not be used + /// for any other purpose, as the values may change as LLDB evolves. + unsigned getResolverID() const { return SubclassID; } + + enum ResolverTy GetResolverTy() { + if (SubclassID > ResolverTy::LastKnownResolverType) + return ResolverTy::UnknownResolver; + else + return (enum ResolverTy)SubclassID; + } + + const char *GetResolverName() { return ResolverTyToName(GetResolverTy()); } + + static const char *ResolverTyToName(enum ResolverTy); + + static ResolverTy NameToResolverTy(llvm::StringRef name); + + virtual lldb::BreakpointResolverSP + CopyForBreakpoint(Breakpoint &breakpoint) = 0; + +protected: + // Used for serializing resolver options: + // The options in this enum and the strings in the + // g_option_names must be kept in sync. + enum class OptionNames : uint32_t { + AddressOffset = 0, + ExactMatch, + FileName, + Inlines, + LanguageName, + LineNumber, + ModuleName, + NameMaskArray, + Offset, + RegexString, + SectionName, + SkipPrologue, + SymbolNameArray, + LastOptionName + }; + static const char + *g_option_names[static_cast(OptionNames::LastOptionName)]; + +public: + static const char *GetKey(OptionNames enum_value) { + return g_option_names[static_cast(enum_value)]; + } + +protected: + //------------------------------------------------------------------ + /// SetSCMatchesByLine - Takes a symbol context list of matches which + /// supposedly represent the same file and + /// line number in a CU, and find the nearest actual line number that matches, + /// and then filter down the + /// matching addresses to unique entries, and skip the prologue if asked to do + /// so, and then set + /// breakpoint locations in this breakpoint for all the resultant addresses. + void SetSCMatchesByLine(SearchFilter &filter, SymbolContextList &sc_list, + bool skip_prologue, llvm::StringRef log_ident); + void SetSCMatchesByLine(SearchFilter &, SymbolContextList &, bool, + const char *) = delete; + + lldb::BreakpointLocationSP AddLocation(Address loc_addr, + bool *new_location = NULL); + + Breakpoint *m_breakpoint; // This is the breakpoint we add locations to. + lldb::addr_t m_offset; // A random offset the user asked us to add to any + // breakpoints we set. + +private: + // Subclass identifier (for llvm isa/dyn_cast) + const unsigned char SubclassID; + DISALLOW_COPY_AND_ASSIGN(BreakpointResolver); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointResolver_h_ diff --git a/include/lldb/Breakpoint/BreakpointResolverAddress.h b/include/lldb/Breakpoint/BreakpointResolverAddress.h new file mode 100644 index 000000000..9d757c885 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointResolverAddress.h @@ -0,0 +1,85 @@ +//===-- 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" +#include "lldb/Core/ModuleSpec.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); + + BreakpointResolverAddress(Breakpoint *bkpt, const Address &addr, + const FileSpec &module_spec); + + ~BreakpointResolverAddress() override; + + static BreakpointResolver * + CreateFromStructuredData(Breakpoint *bkpt, + const StructuredData::Dictionary &options_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + + void ResolveBreakpoint(SearchFilter &filter) override; + + void ResolveBreakpointInModules(SearchFilter &filter, + ModuleList &modules) override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + + void Dump(Stream *s) const override; + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const BreakpointResolverAddress *) { return true; } + static inline bool classof(const BreakpointResolver *V) { + return V->getResolverID() == BreakpointResolver::AddressResolver; + } + + lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override; + +protected: + Address + m_addr; // The address - may be Section Offset or may be just an offset + lldb::addr_t m_resolved_addr; // The current value of the resolved load + // address for this breakpoint, + FileSpec m_module_filespec; // If this filespec is Valid, and m_addr is an + // offset, then it will be converted + // to a Section+Offset address in this module, whenever that module gets + // around to + // being loaded. +private: + DISALLOW_COPY_AND_ASSIGN(BreakpointResolverAddress); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointResolverAddress_h_ diff --git a/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/include/lldb/Breakpoint/BreakpointResolverFileLine.h new file mode 100644 index 000000000..f7bba3d4c --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointResolverFileLine.h @@ -0,0 +1,82 @@ +//===-- 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, lldb::addr_t m_offset, + bool check_inlines, bool skip_prologue, + bool exact_match); + + static BreakpointResolver * + CreateFromStructuredData(Breakpoint *bkpt, + const StructuredData::Dictionary &data_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + + ~BreakpointResolverFileLine() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + + void Dump(Stream *s) const override; + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const BreakpointResolverFileLine *) { + return true; + } + static inline bool classof(const BreakpointResolver *V) { + return V->getResolverID() == BreakpointResolver::FileLineResolver; + } + + lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override; + +protected: + void FilterContexts(SymbolContextList &sc_list); + + friend class Breakpoint; + FileSpec m_file_spec; // This is the file spec we are looking for. + uint32_t m_line_number; // This is the line number that we are looking for. + bool m_inlines; // This determines whether the resolver looks for inlined + // functions or not. + bool m_skip_prologue; + bool m_exact_match; + +private: + DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileLine); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointResolverFileLine_h_ diff --git a/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/include/lldb/Breakpoint/BreakpointResolverFileRegex.h new file mode 100644 index 000000000..d620e99ff --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointResolverFileRegex.h @@ -0,0 +1,85 @@ +//===-- BreakpointResolverFileRegex.h ----------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_BreakpointResolverFileRegex_h_ +#define liblldb_BreakpointResolverFileRegex_h_ + +// C Includes +// C++ Includes +#include +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Utility/ConstString.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class BreakpointResolverFileRegex BreakpointResolverFileRegex.h +/// "lldb/Breakpoint/BreakpointResolverFileRegex.h" +/// @brief This class sets breakpoints by file and line. Optionally, it will +/// look for inlined +/// instances of the file and line specification. +//---------------------------------------------------------------------- + +class BreakpointResolverFileRegex : public BreakpointResolver { +public: + BreakpointResolverFileRegex( + Breakpoint *bkpt, RegularExpression ®ex, + const std::unordered_set &func_name_set, bool exact_match); + + static BreakpointResolver * + CreateFromStructuredData(Breakpoint *bkpt, + const StructuredData::Dictionary &options_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + + ~BreakpointResolverFileRegex() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + + void Dump(Stream *s) const override; + + void AddFunctionName(const char *func_name); + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const BreakpointResolverFileRegex *) { + return true; + } + static inline bool classof(const BreakpointResolver *V) { + return V->getResolverID() == BreakpointResolver::FileRegexResolver; + } + + lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override; + +protected: + friend class Breakpoint; + RegularExpression + m_regex; // This is the line expression that we are looking for. + bool m_exact_match; // If true, then if the source we match is in a comment, + // we won't set a location there. + std::unordered_set m_function_names; // Limit the search to + // functions in the + // comp_unit passed in. + +private: + DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileRegex); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointResolverFileRegex_h_ diff --git a/include/lldb/Breakpoint/BreakpointResolverName.h b/include/lldb/Breakpoint/BreakpointResolverName.h new file mode 100644 index 000000000..c7716d514 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointResolverName.h @@ -0,0 +1,99 @@ +//===-- BreakpointResolverName.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_BreakpointResolverName_h_ +#define liblldb_BreakpointResolverName_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Core/Module.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class BreakpointResolverName BreakpointResolverName.h +/// "lldb/Breakpoint/BreakpointResolverName.h" +/// @brief This class sets breakpoints on a given function name, either by exact +/// match +/// or by regular expression. +//---------------------------------------------------------------------- + +class BreakpointResolverName : public BreakpointResolver { +public: + BreakpointResolverName(Breakpoint *bkpt, const char *name, + uint32_t name_type_mask, lldb::LanguageType language, + Breakpoint::MatchType type, lldb::addr_t offset, + bool skip_prologue); + + // This one takes an array of names. It is always MatchType = Exact. + BreakpointResolverName(Breakpoint *bkpt, const char *names[], + size_t num_names, uint32_t name_type_mask, + lldb::LanguageType language, lldb::addr_t offset, + bool skip_prologue); + + // This one takes a C++ array of names. It is always MatchType = Exact. + BreakpointResolverName(Breakpoint *bkpt, std::vector names, + uint32_t name_type_mask, lldb::LanguageType language, + lldb::addr_t offset, bool skip_prologue); + + // Creates a function breakpoint by regular expression. Takes over control of + // the lifespan of func_regex. + BreakpointResolverName(Breakpoint *bkpt, RegularExpression &func_regex, + lldb::LanguageType language, lldb::addr_t offset, + bool skip_prologue); + + static BreakpointResolver * + CreateFromStructuredData(Breakpoint *bkpt, + const StructuredData::Dictionary &data_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + + ~BreakpointResolverName() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + + void Dump(Stream *s) const override; + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const BreakpointResolverName *) { return true; } + static inline bool classof(const BreakpointResolver *V) { + return V->getResolverID() == BreakpointResolver::NameResolver; + } + + lldb::BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override; + +protected: + BreakpointResolverName(const BreakpointResolverName &rhs); + + std::vector m_lookups; + ConstString m_class_name; + RegularExpression m_regex; + Breakpoint::MatchType m_match_type; + lldb::LanguageType m_language; + bool m_skip_prologue; + + void AddNameLookup(const ConstString &name, uint32_t name_type_mask); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointResolverName_h_ diff --git a/include/lldb/Breakpoint/BreakpointSite.h b/include/lldb/Breakpoint/BreakpointSite.h new file mode 100644 index 000000000..6e9875615 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointSite.h @@ -0,0 +1,287 @@ +//===-- 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 +#include + +// Other libraries and framework includes + +// Project includes +#include "lldb/Breakpoint/BreakpointLocationCollection.h" +#include "lldb/Breakpoint/StoppointLocation.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-forward.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 physical site. When the +/// breakpoint is hit, all the locations are informed by the breakpoint +/// site. Breakpoint sites are owned by the process. +//---------------------------------------------------------------------- + +class BreakpointSite : public std::enable_shared_from_this, + 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 transparently will not + // display any breakpoint opcodes. + }; + + ~BreakpointSite() override; + + //---------------------------------------------------------------------- + // This section manages the breakpoint traps + //---------------------------------------------------------------------- + + //------------------------------------------------------------------ + /// Returns the Opcode Bytes for this breakpoint + //------------------------------------------------------------------ + uint8_t *GetTrapOpcodeBytes(); + + //------------------------------------------------------------------ + /// Returns the Opcode Bytes for this breakpoint - const version + //------------------------------------------------------------------ + const uint8_t *GetTrapOpcodeBytes() const; + + //------------------------------------------------------------------ + /// Get the size of the trap opcode for this address + //------------------------------------------------------------------ + size_t GetTrapOpcodeMaxByteSize() const; + + //------------------------------------------------------------------ + /// Sets the trap opcode + //------------------------------------------------------------------ + bool SetTrapOpcode(const uint8_t *trap_opcode, uint32_t trap_opcode_size); + + //------------------------------------------------------------------ + /// Gets the original instruction bytes that were overwritten by the trap + //------------------------------------------------------------------ + uint8_t *GetSavedOpcodeBytes(); + + //------------------------------------------------------------------ + /// Gets the original instruction bytes that were overwritten by the trap + /// const version + //------------------------------------------------------------------ + const uint8_t *GetSavedOpcodeBytes() const; + + //------------------------------------------------------------------ + /// Says whether \a addr and size \a size intersects with the address \a + /// intersect_addr + //------------------------------------------------------------------ + bool IntersectsRange(lldb::addr_t addr, size_t size, + lldb::addr_t *intersect_addr, size_t *intersect_size, + size_t *opcode_offset) const; + + //------------------------------------------------------------------ + /// Tells whether the current breakpoint site is enabled or not + /// + /// This is a low-level enable bit for the breakpoint sites. If a + /// breakpoint site has no enabled owners, it should just get + /// removed. This enable/disable is for the low-level target code + /// to enable and disable breakpoint sites when single stepping, + /// etc. + //------------------------------------------------------------------ + bool IsEnabled() const; + + //------------------------------------------------------------------ + /// Sets whether the current breakpoint site is enabled or not + /// + /// @param[in] enabled + /// \b true if the breakpoint 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. + //------------------------------------------------------------------ + bool ShouldStop(StoppointCallbackContext *context) override; + + //------------------------------------------------------------------ + /// Standard Dump method + /// + /// @param[in] context + /// The stream to dump this output. + //------------------------------------------------------------------ + void Dump(Stream *s) const override; + + //------------------------------------------------------------------ + /// The "Owners" are the breakpoint locations that share this + /// breakpoint site. The method adds the \a owner to this breakpoint + /// site's owner list. + /// + /// @param[in] context + /// \a owner is the Breakpoint Location to add. + //------------------------------------------------------------------ + void AddOwner(const lldb::BreakpointLocationSP &owner); + + //------------------------------------------------------------------ + /// This method returns the number of breakpoint locations currently + /// located at this breakpoint site. + /// + /// @return + /// The number of owners. + //------------------------------------------------------------------ + size_t GetNumberOfOwners(); + + //------------------------------------------------------------------ + /// This method returns the breakpoint location at index \a index + /// located at this breakpoint site. The owners are listed ordinally + /// from 0 to GetNumberOfOwners() - 1 so you can use this method to iterate + /// over the owners + /// + /// @param[in] index + /// The index in the list of owners for which you wish the owner location. + /// @return + /// A shared pointer to the breakpoint location at that index. + //------------------------------------------------------------------ + lldb::BreakpointLocationSP GetOwnerAtIndex(size_t idx); + + //------------------------------------------------------------------ + /// This method copies the breakpoint site's owners into a new collection. + /// It does this while the owners mutex is locked. + /// + /// @param[out] out_collection + /// The BreakpointLocationCollection into which to put the owners + /// of this breakpoint site. + /// + /// @return + /// The number of elements copied into out_collection. + //------------------------------------------------------------------ + size_t CopyOwnersList(BreakpointLocationCollection &out_collection); + + //------------------------------------------------------------------ + /// Check whether the owners of this breakpoint site have any + /// thread specifiers, and if yes, is \a thread contained in any + /// of these specifiers. + /// + /// @param[in] thread + /// The thread against which to test. + /// + /// return + /// \b true if the collection contains at least one location that + /// would be valid for this thread, false otherwise. + //------------------------------------------------------------------ + bool ValidForThisThread(Thread *thread); + + //------------------------------------------------------------------ + /// Print a description of this breakpoint site to the stream \a s. + /// GetDescription tells you about the breakpoint site's owners. + /// Use BreakpointSite::Dump(Stream *) to get information about the + /// breakpoint site itself. + /// + /// @param[in] s + /// The stream to which to print the description. + /// + /// @param[in] level + /// The description level that indicates the detail level to + /// provide. + /// + /// @see lldb::DescriptionLevel + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level); + + //------------------------------------------------------------------ + /// Tell whether a breakpoint has a location at this site. + /// + /// @param[in] bp_id + /// The breakpoint id to query. + /// + /// @result + /// \b true if bp_id has a location that is at this site, + /// \b false otherwise. + //------------------------------------------------------------------ + bool IsBreakpointAtThisSite(lldb::break_id_t bp_id); + + //------------------------------------------------------------------ + /// Tell whether ALL the breakpoints in the location collection are internal. + /// + /// @result + /// \b true if all breakpoint locations are owned by internal breakpoints, + /// \b false otherwise. + //------------------------------------------------------------------ + bool IsInternal() const; + + BreakpointSite::Type GetType() const { return m_type; } + + void SetType(BreakpointSite::Type type) { m_type = type; } + +private: + friend class Process; + friend class BreakpointLocation; + // The StopInfoBreakpoint knows when it is processing a hit for a thread for a + // site, so let it be the + // one to manage setting the location hit count once and only once. + friend class StopInfoBreakpoint; + + void BumpHitCounts(); + + //------------------------------------------------------------------ + /// The method removes the owner at \a break_loc_id from this breakpoint list. + /// + /// @param[in] context + /// \a break_loc_id is the Breakpoint Location to remove. + //------------------------------------------------------------------ + size_t RemoveOwner(lldb::break_id_t break_id, lldb::break_id_t break_loc_id); + + BreakpointSite::Type m_type; ///< The type of this breakpoint site. + uint8_t m_saved_opcode[8]; ///< The saved opcode bytes if this breakpoint site + ///uses trap opcodes. + uint8_t m_trap_opcode[8]; ///< The opcode that was used to create the + ///breakpoint if it is a software breakpoint site. + bool + m_enabled; ///< Boolean indicating if this breakpoint site enabled or not. + + // Consider adding an optimization where if there is only one + // owner, we don't store a list. The usual case will be only one owner... + BreakpointLocationCollection m_owners; ///< This has the BreakpointLocations + ///that share this breakpoint site. + std::recursive_mutex + m_owners_mutex; ///< This mutex protects the owners collection. + + static lldb::break_id_t GetNextID(); + + // Only the Process can create breakpoint sites in + // Process::CreateBreakpointSite (lldb::BreakpointLocationSP &, bool). + BreakpointSite(BreakpointSiteList *list, + const lldb::BreakpointLocationSP &owner, lldb::addr_t m_addr, + bool use_hardware); + + DISALLOW_COPY_AND_ASSIGN(BreakpointSite); +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointSite_h_ diff --git a/include/lldb/Breakpoint/BreakpointSiteList.h b/include/lldb/Breakpoint/BreakpointSiteList.h new file mode 100644 index 000000000..1431fe799 --- /dev/null +++ b/include/lldb/Breakpoint/BreakpointSiteList.h @@ -0,0 +1,207 @@ +//===-- 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 +#include +#include + +// 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::break_id_t Add(const lldb::BreakpointSiteSP &bp_site_sp); + + //------------------------------------------------------------------ + /// Standard Dump routine, doesn't do anything at present. + /// @param[in] s + /// Stream into which to dump the description. + //------------------------------------------------------------------ + void Dump(Stream *s) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint site at address + /// \a addr. + /// + /// @param[in] addr + /// The address to look for. + /// + /// @result + /// A shared pointer to the breakpoint site. May contain a NULL + /// pointer if no breakpoint site exists with a matching address. + //------------------------------------------------------------------ + lldb::BreakpointSiteSP FindByAddress(lldb::addr_t addr); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint site with id \a breakID. + /// + /// @param[in] breakID + /// The breakpoint site ID to seek for. + /// + /// @result + /// A shared pointer to the breakpoint site. May contain a NULL pointer if + /// the + /// breakpoint doesn't exist. + //------------------------------------------------------------------ + lldb::BreakpointSiteSP FindByID(lldb::break_id_t breakID); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the breakpoint site with id \a breakID - const + /// version. + /// + /// @param[in] breakID + /// The breakpoint site ID to seek for. + /// + /// @result + /// A shared pointer to the breakpoint site. May contain a NULL pointer if + /// the + /// breakpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::BreakpointSiteSP FindByID(lldb::break_id_t breakID) const; + + //------------------------------------------------------------------ + /// Returns the breakpoint site id to the breakpoint site at address \a addr. + /// + /// @param[in] addr + /// The address to match. + /// + /// @result + /// The ID of the breakpoint site, or LLDB_INVALID_BREAK_ID. + //------------------------------------------------------------------ + lldb::break_id_t FindIDByAddress(lldb::addr_t addr); + + //------------------------------------------------------------------ + /// Returns whether the breakpoint site \a bp_site_id has \a bp_id + // as one of its owners. + /// + /// @param[in] bp_site_id + /// The breakpoint site id to query. + /// + /// @param[in] bp_id + /// The breakpoint id to look for in \a bp_site_id. + /// + /// @result + /// True if \a bp_site_id exists in the site list AND \a bp_id is one of the + /// owners of that site. + //------------------------------------------------------------------ + bool BreakpointSiteContainsBreakpoint(lldb::break_id_t bp_site_id, + lldb::break_id_t bp_id); + + void ForEach(std::function const &callback); + + //------------------------------------------------------------------ + /// Removes the breakpoint site given by \b breakID from this list. + /// + /// @param[in] breakID + /// The breakpoint site index to remove. + /// + /// @result + /// \b true if the breakpoint site \a breakID was in the list. + //------------------------------------------------------------------ + bool Remove(lldb::break_id_t breakID); + + //------------------------------------------------------------------ + /// Removes the breakpoint site at address \a addr from this list. + /// + /// @param[in] addr + /// The address from which to remove a breakpoint site. + /// + /// @result + /// \b true if \a addr had a breakpoint site to remove from the list. + //------------------------------------------------------------------ + bool RemoveByAddress(lldb::addr_t addr); + + bool FindInRange(lldb::addr_t lower_bound, lldb::addr_t upper_bound, + BreakpointSiteList &bp_site_list) const; + + typedef void (*BreakpointSiteSPMapFunc)(lldb::BreakpointSiteSP &bp, + void *baton); + + //------------------------------------------------------------------ + /// Enquires of the breakpoint site on in this list with ID \a breakID whether + /// we should stop for the breakpoint or not. + /// + /// @param[in] context + /// This contains the information about this stop. + /// + /// @param[in] breakID + /// This break ID that we hit. + /// + /// @return + /// \b true if we should stop, \b false otherwise. + //------------------------------------------------------------------ + bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID); + + //------------------------------------------------------------------ + /// Returns the number of elements in the list. + /// + /// @result + /// The number of elements. + //------------------------------------------------------------------ + size_t GetSize() const { + std::lock_guard guard(m_mutex); + return m_bp_site_list.size(); + } + + bool IsEmpty() const { + std::lock_guard guard(m_mutex); + return m_bp_site_list.empty(); + } + +protected: + typedef std::map collection; + + collection::iterator GetIDIterator(lldb::break_id_t breakID); + + collection::const_iterator GetIDConstIterator(lldb::break_id_t breakID) const; + + mutable std::recursive_mutex m_mutex; + collection m_bp_site_list; // The breakpoint site list. +}; + +} // namespace lldb_private + +#endif // liblldb_BreakpointSiteList_h_ diff --git a/include/lldb/Breakpoint/Stoppoint.h b/include/lldb/Breakpoint/Stoppoint.h new file mode 100644 index 000000000..3195ef942 --- /dev/null +++ b/include/lldb/Breakpoint/Stoppoint.h @@ -0,0 +1,56 @@ +//===-- 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/Utility/UserID.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class Stoppoint { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + Stoppoint(); + + virtual ~Stoppoint(); + + //------------------------------------------------------------------ + // Methods + //------------------------------------------------------------------ + virtual void Dump(Stream *) = 0; + + virtual bool IsEnabled() = 0; + + virtual void SetEnabled(bool enable) = 0; + + lldb::break_id_t GetID() const; + + void SetID(lldb::break_id_t bid); + +protected: + lldb::break_id_t m_bid; + +private: + //------------------------------------------------------------------ + // For Stoppoint only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(Stoppoint); +}; + +} // namespace lldb_private + +#endif // liblldb_Stoppoint_h_ diff --git a/include/lldb/Breakpoint/StoppointCallbackContext.h b/include/lldb/Breakpoint/StoppointCallbackContext.h new file mode 100644 index 000000000..268058484 --- /dev/null +++ b/include/lldb/Breakpoint/StoppointCallbackContext.h @@ -0,0 +1,63 @@ +//===-- 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/Target/ExecutionContext.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class StoppointCallbackContext StoppointCallbackContext.h +/// "lldb/Breakpoint/StoppointCallbackContext.h" +/// @brief Class holds the information that a breakpoint callback needs to +/// evaluate this stop. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +/// General Outline: +/// When we hit a breakpoint we need to package up whatever information is +/// needed +/// to evaluate breakpoint commands and conditions. This class is the container +/// of +/// that information. +//---------------------------------------------------------------------- + +class StoppointCallbackContext { +public: + StoppointCallbackContext(); + + StoppointCallbackContext(Event *event, const ExecutionContext &exe_ctx, + bool synchronously = false); + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Sets the event, process and thread to NULL, and the frame index to an + /// invalid value. + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + Event *event; // This is the event, the callback can modify this to indicate + // the meaning of the breakpoint hit + ExecutionContextRef + exe_ctx_ref; // This tells us where we have stopped, what thread. + bool is_synchronous; // Is the callback being executed synchronously with the + // breakpoint, + // or asynchronously as the event is retrieved? +}; + +} // namespace lldb_private + +#endif // liblldb_StoppointCallbackContext_h_ diff --git a/include/lldb/Breakpoint/StoppointLocation.h b/include/lldb/Breakpoint/StoppointLocation.h new file mode 100644 index 000000000..f64035bbb --- /dev/null +++ b/include/lldb/Breakpoint/StoppointLocation.h @@ -0,0 +1,101 @@ +//===-- 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/Utility/UserID.h" +#include "lldb/lldb-private.h" +// #include "lldb/Breakpoint/BreakpointOptions.h" + +namespace lldb_private { + +class StoppointLocation { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + StoppointLocation(lldb::break_id_t bid, lldb::addr_t m_addr, bool hardware); + + StoppointLocation(lldb::break_id_t bid, lldb::addr_t m_addr, + uint32_t byte_size, bool hardware); + + virtual ~StoppointLocation(); + + //------------------------------------------------------------------ + // Operators + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + // Methods + //------------------------------------------------------------------ + virtual lldb::addr_t GetLoadAddress() const { return m_addr; } + + virtual void SetLoadAddress(lldb::addr_t addr) { m_addr = addr; } + + uint32_t GetByteSize() const { return m_byte_size; } + + uint32_t GetHitCount() const { return m_hit_count; } + + uint32_t GetHardwareIndex() const { return m_hardware_index; } + + bool HardwareRequired() const { return m_hardware; } + + virtual bool IsHardware() const { + return m_hardware_index != LLDB_INVALID_INDEX32; + } + + virtual bool ShouldStop(StoppointCallbackContext *context) { return true; } + + virtual void Dump(Stream *stream) const {} + + void SetHardwareIndex(uint32_t index) { m_hardware_index = index; } + + lldb::break_id_t GetID() const { return m_loc_id; } + +protected: + //------------------------------------------------------------------ + // Classes that inherit from StoppointLocation can see and modify these + //------------------------------------------------------------------ + lldb::break_id_t m_loc_id; // Stoppoint location ID + lldb::addr_t + m_addr; // The load address of this stop point. The base Stoppoint doesn't + // store a full Address since that's not needed for the breakpoint sites. + bool m_hardware; // True if this point has been is required to use hardware + // (which may fail due to lack of resources) + uint32_t m_hardware_index; // The hardware resource index for this + // breakpoint/watchpoint + uint32_t m_byte_size; // The size in bytes of stop location. e.g. the length + // of the trap opcode for + // software breakpoints, or the optional length in bytes for + // hardware breakpoints, or the length of the watchpoint. + uint32_t + m_hit_count; // Number of times this breakpoint/watchpoint has been hit + + // If you override this, be sure to call the base class to increment the + // internal counter. + void IncrementHitCount() { ++m_hit_count; } + + void DecrementHitCount(); + +private: + //------------------------------------------------------------------ + // For StoppointLocation only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(StoppointLocation); + StoppointLocation(); // Disallow default constructor +}; + +} // namespace lldb_private + +#endif // liblldb_StoppointLocation_h_ diff --git a/include/lldb/Breakpoint/Watchpoint.h b/include/lldb/Breakpoint/Watchpoint.h new file mode 100644 index 000000000..69067a567 --- /dev/null +++ b/include/lldb/Breakpoint/Watchpoint.h @@ -0,0 +1,236 @@ +//===-- Watchpoint.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Watchpoint_h_ +#define liblldb_Watchpoint_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/StoppointLocation.h" +#include "lldb/Breakpoint/WatchpointOptions.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class Watchpoint : public std::enable_shared_from_this, + public StoppointLocation { +public: + class WatchpointEventData : public EventData { + public: + WatchpointEventData(lldb::WatchpointEventType sub_type, + const lldb::WatchpointSP &new_watchpoint_sp); + + ~WatchpointEventData() override; + + static const ConstString &GetFlavorString(); + + const ConstString &GetFlavor() const override; + + lldb::WatchpointEventType GetWatchpointEventType() const; + + lldb::WatchpointSP &GetWatchpoint(); + + void Dump(Stream *s) const override; + + static lldb::WatchpointEventType + GetWatchpointEventTypeFromEvent(const lldb::EventSP &event_sp); + + static lldb::WatchpointSP + GetWatchpointFromEvent(const lldb::EventSP &event_sp); + + static const WatchpointEventData * + GetEventDataFromEvent(const Event *event_sp); + + private: + lldb::WatchpointEventType m_watchpoint_event; + lldb::WatchpointSP m_new_watchpoint_sp; + + DISALLOW_COPY_AND_ASSIGN(WatchpointEventData); + }; + + Watchpoint(Target &target, lldb::addr_t addr, uint32_t size, + const CompilerType *type, bool hardware = true); + + ~Watchpoint() override; + + void IncrementFalseAlarmsAndReviseHitCount(); + + bool IsEnabled() const; + + // This doesn't really enable/disable the watchpoint. + // It is currently just for use in the Process plugin's + // {Enable,Disable}Watchpoint, which should be used instead. + + void SetEnabled(bool enabled, bool notify = true); + + bool IsHardware() const override; + + bool ShouldStop(StoppointCallbackContext *context) override; + + bool WatchpointRead() const; + bool WatchpointWrite() const; + uint32_t GetIgnoreCount() const; + void SetIgnoreCount(uint32_t n); + void SetWatchpointType(uint32_t type, bool notify = true); + void SetDeclInfo(const std::string &str); + std::string GetWatchSpec(); + void SetWatchSpec(const std::string &str); + + // Snapshot management interface. + bool IsWatchVariable() const; + void SetWatchVariable(bool val); + bool CaptureWatchedValue(const ExecutionContext &exe_ctx); + + void GetDescription(Stream *s, lldb::DescriptionLevel level); + void Dump(Stream *s) const override; + void DumpSnapshots(Stream *s, const char *prefix = nullptr) const; + void DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const; + Target &GetTarget() { return m_target; } + const Status &GetError() { return m_error; } + + //------------------------------------------------------------------ + /// Returns the WatchpointOptions structure set for this watchpoint. + /// + /// @return + /// A pointer to this watchpoint's WatchpointOptions. + //------------------------------------------------------------------ + WatchpointOptions *GetOptions() { return &m_options; } + + //------------------------------------------------------------------ + /// Set the callback action invoked when the watchpoint is hit. + /// + /// @param[in] callback + /// The method that will get called when the watchpoint is hit. + /// @param[in] callback_baton + /// A void * pointer that will get passed back to the callback function. + /// @param[in] is_synchronous + /// If \b true the callback will be run on the private event thread + /// before the stop event gets reported. If false, the callback will get + /// handled on the public event thread after the stop has been posted. + /// + /// @return + /// \b true if the process should stop when you hit the watchpoint. + /// \b false if it should continue. + //------------------------------------------------------------------ + void SetCallback(WatchpointHitCallback callback, void *callback_baton, + bool is_synchronous = false); + + void SetCallback(WatchpointHitCallback callback, + const lldb::BatonSP &callback_baton_sp, + bool is_synchronous = false); + + void ClearCallback(); + + //------------------------------------------------------------------ + /// Invoke the callback action when the watchpoint is hit. + /// + /// @param[in] context + /// Described the watchpoint event. + /// + /// @return + /// \b true if the target should stop at this watchpoint and \b false not. + //------------------------------------------------------------------ + bool InvokeCallback(StoppointCallbackContext *context); + + //------------------------------------------------------------------ + // Condition + //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// Set the watchpoint's condition. + /// + /// @param[in] condition + /// The condition expression to evaluate when the watchpoint is hit. + /// Pass in nullptr to clear the condition. + //------------------------------------------------------------------ + void SetCondition(const char *condition); + + //------------------------------------------------------------------ + /// Return a pointer to the text of the condition expression. + /// + /// @return + /// A pointer to the condition expression text, or nullptr if no + // condition has been set. + //------------------------------------------------------------------ + const char *GetConditionText() const; + + void TurnOnEphemeralMode(); + + void TurnOffEphemeralMode(); + + bool IsDisabledDuringEphemeralMode(); + + const CompilerType &GetCompilerType() { return m_type; } + +private: + friend class Target; + friend class WatchpointList; + + void ResetHitCount() { m_hit_count = 0; } + + void ResetHistoricValues() { + m_old_value_sp.reset(nullptr); + m_new_value_sp.reset(nullptr); + } + + Target &m_target; + bool m_enabled; // Is this watchpoint enabled + bool m_is_hardware; // Is this a hardware watchpoint + bool m_is_watch_variable; // True if set via 'watchpoint set variable'. + bool m_is_ephemeral; // True if the watchpoint is in the ephemeral mode, + // meaning that it is + // undergoing a pair of temporary disable/enable actions to avoid recursively + // triggering further watchpoint events. + uint32_t m_disabled_count; // Keep track of the count that the watchpoint is + // disabled while in ephemeral mode. + // At the end of the ephemeral mode when the watchpoint is to be enabled + // again, + // we check the count, if it is more than 1, it means the user-supplied + // actions + // actually want the watchpoint to be disabled! + uint32_t m_watch_read : 1, // 1 if we stop when the watched data is read from + m_watch_write : 1, // 1 if we stop when the watched data is written to + m_watch_was_read : 1, // Set to 1 when watchpoint is hit for a read access + m_watch_was_written : 1; // Set to 1 when watchpoint is hit for a write + // access + uint32_t m_ignore_count; // Number of times to ignore this watchpoint + uint32_t m_false_alarms; // Number of false alarms. + std::string m_decl_str; // Declaration information, if any. + std::string m_watch_spec_str; // Spec for the watchpoint. + lldb::ValueObjectSP m_old_value_sp; + lldb::ValueObjectSP m_new_value_sp; + CompilerType m_type; + Status m_error; // An error object describing errors associated with this + // watchpoint. + WatchpointOptions + m_options; // Settable watchpoint options, which is a delegate to handle + // the callback machinery. + bool m_being_created; + + std::unique_ptr m_condition_ap; // The condition to test. + + void SetID(lldb::watch_id_t id) { m_loc_id = id; } + + void SendWatchpointChangedEvent(lldb::WatchpointEventType eventKind); + + void SendWatchpointChangedEvent(WatchpointEventData *data); + + DISALLOW_COPY_AND_ASSIGN(Watchpoint); +}; + +} // namespace lldb_private + +#endif // liblldb_Watchpoint_h_ diff --git a/include/lldb/Breakpoint/WatchpointList.h b/include/lldb/Breakpoint/WatchpointList.h new file mode 100644 index 000000000..9abac9167 --- /dev/null +++ b/include/lldb/Breakpoint/WatchpointList.h @@ -0,0 +1,253 @@ +//===-- WatchpointList.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_WatchpointList_h_ +#define liblldb_WatchpointList_h_ + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Address.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class WatchpointList WatchpointList.h "lldb/Breakpoint/WatchpointList.h" +/// @brief This class is used by Watchpoint to manage a list of watchpoints, +// each watchpoint in the list has a unique ID, and is unique by Address as +// well. +//---------------------------------------------------------------------- + +class WatchpointList { + // Only Target can make the watchpoint list, or add elements to it. + // This is not just some random collection of watchpoints. Rather, the act of + // adding the watchpoint to this list sets its ID. + friend class Watchpoint; + friend class Target; + +public: + //------------------------------------------------------------------ + /// Default constructor makes an empty list. + //------------------------------------------------------------------ + WatchpointList(); + + //------------------------------------------------------------------ + /// Destructor, currently does nothing. + //------------------------------------------------------------------ + ~WatchpointList(); + + //------------------------------------------------------------------ + /// Add a Watchpoint to the list. + /// + /// @param[in] wp_sp + /// A shared pointer to a watchpoint being added to the list. + /// + /// @return + /// The ID of the Watchpoint in the list. + //------------------------------------------------------------------ + lldb::watch_id_t Add(const lldb::WatchpointSP &wp_sp, bool notify); + + //------------------------------------------------------------------ + /// Standard "Dump" method. + //------------------------------------------------------------------ + void Dump(Stream *s) const; + + //------------------------------------------------------------------ + /// Dump with lldb::DescriptionLevel. + //------------------------------------------------------------------ + void DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the watchpoint at address + /// \a addr - + /// const version. + /// + /// @param[in] addr + /// The address to look for. + /// + /// @result + /// A shared pointer to the watchpoint. May contain a NULL + /// pointer if the watchpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::WatchpointSP FindByAddress(lldb::addr_t addr) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the watchpoint with watchpoint spec + /// \a spec - + /// const version. + /// + /// @param[in] spec + /// The watchpoint spec to look for. + /// + /// @result + /// A shared pointer to the watchpoint. May contain a NULL + /// pointer if the watchpoint doesn't exist. + //------------------------------------------------------------------ + const lldb::WatchpointSP FindBySpec(std::string spec) const; + + //------------------------------------------------------------------ + /// Returns a shared pointer to the watchpoint with id + /// \a watchID, const + /// version. + /// + /// @param[in] watchID + /// The watchpoint location ID to seek for. + /// + /// @result + /// A shared pointer to the watchpoint. May contain a NULL + /// pointer if the watchpoint doesn't exist. + //------------------------------------------------------------------ + lldb::WatchpointSP FindByID(lldb::watch_id_t watchID) const; + + //------------------------------------------------------------------ + /// Returns the watchpoint id to the watchpoint + /// at address \a addr. + /// + /// @param[in] addr + /// The address to match. + /// + /// @result + /// The ID of the watchpoint, or LLDB_INVALID_WATCH_ID. + //------------------------------------------------------------------ + lldb::watch_id_t FindIDByAddress(lldb::addr_t addr); + + //------------------------------------------------------------------ + /// Returns the watchpoint id to the watchpoint + /// with watchpoint spec \a spec. + /// + /// @param[in] spec + /// The watchpoint spec to match. + /// + /// @result + /// The ID of the watchpoint, or LLDB_INVALID_WATCH_ID. + //------------------------------------------------------------------ + lldb::watch_id_t FindIDBySpec(std::string spec); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the watchpoint with index \a i. + /// + /// @param[in] i + /// The watchpoint index to seek for. + /// + /// @result + /// A shared pointer to the watchpoint. May contain a NULL pointer if + /// the watchpoint doesn't exist. + //------------------------------------------------------------------ + lldb::WatchpointSP GetByIndex(uint32_t i); + + //------------------------------------------------------------------ + /// Returns a shared pointer to the watchpoint with index \a i, const + /// version. + /// + /// @param[in] i + /// The watchpoint index to seek for. + /// + /// @result + /// A shared pointer to the watchpoint. May contain a NULL pointer if + /// the watchpoint location doesn't exist. + //------------------------------------------------------------------ + const lldb::WatchpointSP GetByIndex(uint32_t i) const; + + //------------------------------------------------------------------ + /// Removes the watchpoint given by \b watchID from this list. + /// + /// @param[in] watchID + /// The watchpoint ID to remove. + /// + /// @result + /// \b true if the watchpoint \a watchID was in the list. + //------------------------------------------------------------------ + bool Remove(lldb::watch_id_t watchID, bool notify); + + //------------------------------------------------------------------ + /// Returns the number hit count of all watchpoints in this list. + /// + /// @result + /// Hit count of all watchpoints in this list. + //------------------------------------------------------------------ + uint32_t GetHitCount() const; + + //------------------------------------------------------------------ + /// Enquires of the watchpoint in this list with ID \a watchID whether we + /// should stop. + /// + /// @param[in] context + /// This contains the information about this stop. + /// + /// @param[in] watchID + /// This watch ID that we hit. + /// + /// @return + /// \b true if we should stop, \b false otherwise. + //------------------------------------------------------------------ + bool ShouldStop(StoppointCallbackContext *context, lldb::watch_id_t watchID); + + //------------------------------------------------------------------ + /// Returns the number of elements in this watchpoint list. + /// + /// @result + /// The number of elements. + //------------------------------------------------------------------ + size_t GetSize() const { + std::lock_guard guard(m_mutex); + return m_watchpoints.size(); + } + + //------------------------------------------------------------------ + /// Print a description of the watchpoints in this list to the stream \a s. + /// + /// @param[in] s + /// The stream to which to print the description. + /// + /// @param[in] level + /// The description level that indicates the detail level to + /// provide. + /// + /// @see lldb::DescriptionLevel + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level); + + void SetEnabledAll(bool enabled); + + void RemoveAll(bool notify); + + //------------------------------------------------------------------ + /// Sets the passed in Locker to hold the Watchpoint List mutex. + /// + /// @param[in] locker + /// The locker object that is set. + //------------------------------------------------------------------ + void GetListMutex(std::unique_lock &lock); + +protected: + typedef std::list wp_collection; + typedef std::vector id_vector; + + id_vector GetWatchpointIDs() const; + + wp_collection::iterator GetIDIterator(lldb::watch_id_t watchID); + + wp_collection::const_iterator + GetIDConstIterator(lldb::watch_id_t watchID) const; + + wp_collection m_watchpoints; + mutable std::recursive_mutex m_mutex; + + lldb::watch_id_t m_next_wp_id; +}; + +} // namespace lldb_private + +#endif // liblldb_WatchpointList_h_ diff --git a/include/lldb/Breakpoint/WatchpointOptions.h b/include/lldb/Breakpoint/WatchpointOptions.h new file mode 100644 index 000000000..6ab1264a1 --- /dev/null +++ b/include/lldb/Breakpoint/WatchpointOptions.h @@ -0,0 +1,246 @@ +//===-- WatchpointOptions.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_WatchpointOptions_h_ +#define liblldb_WatchpointOptions_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Baton.h" +#include "lldb/Utility/StringList.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class WatchpointOptions WatchpointOptions.h +/// "lldb/Breakpoint/WatchpointOptions.h" +/// @brief Class that manages the options on a watchpoint. +//---------------------------------------------------------------------- + +class WatchpointOptions { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + //------------------------------------------------------------------ + /// Default constructor. The watchpoint is enabled, and has no condition, + /// callback, ignore count, etc... + //------------------------------------------------------------------ + WatchpointOptions(); + WatchpointOptions(const WatchpointOptions &rhs); + + static WatchpointOptions *CopyOptionsNoCallback(WatchpointOptions &rhs); + //------------------------------------------------------------------ + /// This constructor allows you to specify all the watchpoint options. + /// + /// @param[in] callback + /// This is the plugin for some code that gets run, returns \b true if we + /// are to stop. + /// + /// @param[in] baton + /// Client data that will get passed to the callback. + /// + /// @param[in] thread_id + /// Only stop if \a thread_id hits the watchpoint. + //------------------------------------------------------------------ + WatchpointOptions(WatchpointHitCallback callback, void *baton, + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + + virtual ~WatchpointOptions(); + + //------------------------------------------------------------------ + // Operators + //------------------------------------------------------------------ + const WatchpointOptions &operator=(const WatchpointOptions &rhs); + + //------------------------------------------------------------------ + // Callbacks + // + // Watchpoint callbacks come in two forms, synchronous and asynchronous. + // Synchronous callbacks will get + // run before any of the thread plans are consulted, and if they return false + // the target will continue + // "under the radar" of the thread plans. There are a couple of restrictions + // to synchronous callbacks: + // 1) They should NOT resume the target themselves. Just return false if you + // want the target to restart. + // 2) Watchpoints with synchronous callbacks can't have conditions (or rather, + // they can have them, but they + // won't do anything. Ditto with ignore counts, etc... You are supposed + // to control that all through the + // callback. + // Asynchronous callbacks get run as part of the "ShouldStop" logic in the + // thread plan. The logic there is: + // a) If the watchpoint is thread specific and not for this thread, continue + // w/o running the callback. + // b) If the ignore count says we shouldn't stop, then ditto. + // c) If the condition says we shouldn't stop, then ditto. + // d) Otherwise, the callback will get run, and if it returns true we will + // stop, and if false we won't. + // The asynchronous callback can run the target itself, but at present that + // should be the last action the + // callback does. We will relax this condition at some point, but it will + // take a bit of plumbing to get + // that to work. + // + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Adds a callback to the watchpoint option set. + /// + /// @param[in] callback + /// The function to be called when the watchpoint gets hit. + /// + /// @param[in] baton_sp + /// A baton which will get passed back to the callback when it is invoked. + /// + /// @param[in] synchronous + /// Whether this is a synchronous or asynchronous callback. See discussion + /// above. + //------------------------------------------------------------------ + void SetCallback(WatchpointHitCallback callback, + const lldb::BatonSP &baton_sp, bool synchronous = false); + + //------------------------------------------------------------------ + /// Remove the callback from this option set. + //------------------------------------------------------------------ + void ClearCallback(); + + // The rest of these functions are meant to be used only within the watchpoint + // handling mechanism. + + //------------------------------------------------------------------ + /// Use this function to invoke the callback for a specific stop. + /// + /// @param[in] context + /// The context in which the callback is to be invoked. This includes the + /// stop event, the + /// execution context of the stop (since you might hit the same watchpoint + /// on multiple threads) and + /// whether we are currently executing synchronous or asynchronous + /// callbacks. + /// + /// @param[in] watch_id + /// The watchpoint ID that owns this option set. + /// + /// @return + /// The callback return value. + //------------------------------------------------------------------ + bool InvokeCallback(StoppointCallbackContext *context, + lldb::user_id_t watch_id); + + //------------------------------------------------------------------ + /// Used in InvokeCallback to tell whether it is the right time to run this + /// kind of callback. + /// + /// @return + /// The synchronicity of our callback. + //------------------------------------------------------------------ + bool IsCallbackSynchronous() { return m_callback_is_synchronous; } + + //------------------------------------------------------------------ + /// Fetch the baton from the callback. + /// + /// @return + /// The baton. + //------------------------------------------------------------------ + Baton *GetBaton(); + + //------------------------------------------------------------------ + /// Fetch a const version of the baton from the callback. + /// + /// @return + /// The baton. + //------------------------------------------------------------------ + const Baton *GetBaton() const; + + //------------------------------------------------------------------ + /// Return the current thread spec for this option. This will return nullptr + /// if the no thread + /// specifications have been set for this Option yet. + /// @return + /// The thread specification pointer for this option, or nullptr if none + /// has + /// been set yet. + //------------------------------------------------------------------ + const ThreadSpec *GetThreadSpecNoCreate() const; + + //------------------------------------------------------------------ + /// Returns a pointer to the ThreadSpec for this option, creating it. + /// if it hasn't been created already. This API is used for setting the + /// ThreadSpec items for this option. + //------------------------------------------------------------------ + ThreadSpec *GetThreadSpec(); + + void SetThreadID(lldb::tid_t thread_id); + + void GetDescription(Stream *s, lldb::DescriptionLevel level) const; + + //------------------------------------------------------------------ + /// Get description for callback only. + //------------------------------------------------------------------ + void GetCallbackDescription(Stream *s, lldb::DescriptionLevel level) const; + + //------------------------------------------------------------------ + /// Returns true if the watchpoint option has a callback set. + //------------------------------------------------------------------ + bool HasCallback(); + + //------------------------------------------------------------------ + /// This is the default empty callback. + /// @return + /// The thread id for which the watchpoint hit will stop, + /// LLDB_INVALID_THREAD_ID for all threads. + //------------------------------------------------------------------ + static bool NullCallback(void *baton, StoppointCallbackContext *context, + lldb::user_id_t watch_id); + + struct CommandData { + CommandData() : user_source(), script_source(), stop_on_error(true) {} + + ~CommandData() = default; + + StringList user_source; + std::string script_source; + bool stop_on_error; + }; + + class CommandBaton : public TypedBaton { + public: + CommandBaton(std::unique_ptr Data) + : TypedBaton(std::move(Data)) {} + + void GetDescription(Stream *s, lldb::DescriptionLevel level) const override; + }; + +protected: + //------------------------------------------------------------------ + // Classes that inherit from WatchpointOptions can see and modify these + //------------------------------------------------------------------ + +private: + //------------------------------------------------------------------ + // For WatchpointOptions only + //------------------------------------------------------------------ + WatchpointHitCallback m_callback; // This is the callback function pointer + lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback + bool m_callback_is_synchronous; + std::unique_ptr + m_thread_spec_ap; // Thread for which this watchpoint will take +}; + +} // namespace lldb_private + +#endif // liblldb_WatchpointOptions_h_ diff --git a/include/lldb/Core/Address.h b/include/lldb/Core/Address.h new file mode 100644 index 000000000..4c7745806 --- /dev/null +++ b/include/lldb/Core/Address.h @@ -0,0 +1,581 @@ +//===-- 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_ + +#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS +#include "lldb/lldb-enumerations.h" // for AddressClass::eAddressClassInvalid +#include "lldb/lldb-forward.h" // for SectionWP, SectionSP, ModuleSP +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t +#include // for uint32_t, UINT32_MAX, int64_t + +namespace lldb_private { +class Block; +} +namespace lldb_private { +class CompileUnit; +} +namespace lldb_private { +class ExecutionContextScope; +} +namespace lldb_private { +class Function; +} +namespace lldb_private { +class SectionList; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class Symbol; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class Target; +} +namespace lldb_private { +struct LineEntry; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Address Address.h "lldb/Core/Address.h" +/// @brief A section + offset based address class. +/// +/// The Address class allows addresses to be relative to a section +/// that can move during runtime due to images (executables, shared +/// libraries, bundles, frameworks) being loaded at different +/// addresses than the addresses found in the object file that +/// represents them on disk. There are currently two types of addresses +/// for a section: +/// @li file addresses +/// @li load addresses +/// +/// File addresses represent the virtual addresses that are in the "on +/// disk" object files. These virtual addresses are converted to be +/// relative to unique sections scoped to the object file so that +/// when/if the addresses slide when the images are loaded/unloaded +/// in memory, we can easily track these changes without having to +/// update every object (compile unit ranges, line tables, function +/// address ranges, lexical block and inlined subroutine address +/// ranges, global and static variables) each time an image is loaded or +/// unloaded. +/// +/// Load addresses represent the virtual addresses where each section +/// ends up getting loaded at runtime. Before executing a program, it +/// is common for all of the load addresses to be unresolved. When a +/// DynamicLoader plug-in receives notification that shared libraries +/// have been loaded/unloaded, the load addresses of the main executable +/// and any images (shared libraries) will be resolved/unresolved. When +/// this happens, breakpoints that are in one of these sections can be +/// set/cleared. +//---------------------------------------------------------------------- +class Address { +public: + //------------------------------------------------------------------ + /// Dump styles allow the Address::Dump(Stream *,DumpStyle) const + /// function to display Address contents in a variety of ways. + //------------------------------------------------------------------ + typedef enum { + DumpStyleInvalid, ///< Invalid dump style + DumpStyleSectionNameOffset, ///< Display as the section name + offset. + ///< \code + /// // address for printf in libSystem.B.dylib as a section name + offset + /// libSystem.B.dylib.__TEXT.__text + 0x0005cfdf + /// \endcode + DumpStyleSectionPointerOffset, ///< Display as the section pointer + offset + ///(debug output). + ///< \code + /// // address for printf in libSystem.B.dylib as a section pointer + offset + /// (lldb::Section *)0x35cc50 + 0x000000000005cfdf \endcode + DumpStyleFileAddress, ///< Display as the file address (if any). + ///< \code + /// // address for printf in libSystem.B.dylib as a file address + /// 0x000000000005dcff \endcode + DumpStyleModuleWithFileAddress, ///< Display as the file address with the + ///module name prepended (if any). + ///< \code + /// // address for printf in libSystem.B.dylib as a file address + /// libSystem.B.dylib[0x000000000005dcff] \endcode + DumpStyleLoadAddress, ///< Display as the load address (if resolved). + ///< \code + /// // address for printf in libSystem.B.dylib as a load address + /// 0x00007fff8306bcff \endcode + DumpStyleResolvedDescription, ///< Display the details about what an address + ///resolves to. This can + ///< be anything from a symbol context summary (module, function/symbol, + ///< and file and line), to information about what the pointer points to + ///< if the address is in a section (section of pointers, c strings, etc). + DumpStyleResolvedDescriptionNoModule, + DumpStyleResolvedDescriptionNoFunctionArguments, + DumpStyleNoFunctionName, ///< Elide the function name; display an offset + ///into the current function. + ///< Used primarily in disassembly symbolication + DumpStyleDetailedSymbolContext, ///< Detailed symbol context information for + ///an address for all symbol + ///< context members. + DumpStyleResolvedPointerDescription ///< Dereference a pointer at the + ///current address and then lookup the + ///< dereferenced address using DumpStyleResolvedDescription + } DumpStyle; + + //------------------------------------------------------------------ + /// Default constructor. + /// + /// Initialize with a invalid section (NULL) and an invalid + /// offset (LLDB_INVALID_ADDRESS). + //------------------------------------------------------------------ + Address() : m_section_wp(), m_offset(LLDB_INVALID_ADDRESS) {} + + //------------------------------------------------------------------ + /// Copy constructor + /// + /// Makes a copy of the another Address object \a rhs. + /// + /// @param[in] rhs + /// A const Address object reference to copy. + //------------------------------------------------------------------ + Address(const Address &rhs) + : m_section_wp(rhs.m_section_wp), m_offset(rhs.m_offset) {} + + //------------------------------------------------------------------ + /// Construct with a section pointer and offset. + /// + /// Initialize the address with the supplied \a section and \a + /// offset. + /// + /// @param[in] section + /// A section pointer to a valid lldb::Section, or NULL if the + /// address doesn't have a section or will get resolved later. + /// + /// @param[in] offset + /// The offset in bytes into \a section. + //------------------------------------------------------------------ + Address(const lldb::SectionSP §ion_sp, lldb::addr_t offset) + : m_section_wp(), // Don't init with section_sp in case section_sp is + // invalid (the weak_ptr will throw) + m_offset(offset) { + if (section_sp) + m_section_wp = section_sp; + } + + //------------------------------------------------------------------ + /// Construct with a virtual address and section list. + /// + /// Initialize and resolve the address with the supplied virtual + /// address \a file_addr. + /// + /// @param[in] file_addr + /// A virtual file address. + /// + /// @param[in] section_list + /// A list of sections, one of which may contain the \a file_addr. + //------------------------------------------------------------------ + Address(lldb::addr_t file_addr, const SectionList *section_list); + + Address(lldb::addr_t abs_addr); + +//------------------------------------------------------------------ +/// Assignment operator. +/// +/// Copies the address value from another Address object \a rhs +/// into \a this object. +/// +/// @param[in] rhs +/// A const Address object reference to copy. +/// +/// @return +/// A const Address object reference to \a this. +//------------------------------------------------------------------ +#ifndef SWIG + const Address &operator=(const Address &rhs); +#endif + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Sets the section to an invalid value (NULL) and an invalid + /// offset (LLDB_INVALID_ADDRESS). + //------------------------------------------------------------------ + void Clear() { + m_section_wp.reset(); + m_offset = LLDB_INVALID_ADDRESS; + } + + //------------------------------------------------------------------ + /// Compare two Address objects. + /// + /// @param[in] lhs + /// The Left Hand Side const Address object reference. + /// + /// @param[in] rhs + /// The Right Hand Side const Address object reference. + /// + /// @return + /// @li -1 if lhs < rhs + /// @li 0 if lhs == rhs + /// @li 1 if lhs > rhs + //------------------------------------------------------------------ + static int CompareFileAddress(const Address &lhs, const Address &rhs); + + static int CompareLoadAddress(const Address &lhs, const Address &rhs, + Target *target); + + static int CompareModulePointerAndOffset(const Address &lhs, + const Address &rhs); + + // For use with std::map, std::multi_map + class ModulePointerAndOffsetLessThanFunctionObject { + public: + ModulePointerAndOffsetLessThanFunctionObject() = default; + + 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 description. + /// + /// @param[in] style + /// The display style for the address. + /// + /// @param[in] fallback_style + /// The display style for the address. + /// + /// @return + /// Returns \b true if the address was able to be displayed. + /// File and load addresses may be unresolved and it may not be + /// possible to display a valid value, \b false will be returned + /// in such cases. + /// + /// @see Address::DumpStyle + //------------------------------------------------------------------ + bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, + DumpStyle fallback_style = DumpStyleInvalid, + uint32_t addr_byte_size = UINT32_MAX) const; + + lldb::AddressClass GetAddressClass() const; + + //------------------------------------------------------------------ + /// Get the file address. + /// + /// If an address comes from a file on disk that has section + /// relative addresses, then it has a virtual address that is + /// relative to unique section in the object file. + /// + /// @return + /// The valid file virtual address, or LLDB_INVALID_ADDRESS if + /// the address doesn't have a file virtual address (image is + /// from memory only with no representation on disk). + //------------------------------------------------------------------ + lldb::addr_t GetFileAddress() const; + + //------------------------------------------------------------------ + /// Get the load address. + /// + /// If an address comes from a file on disk that has section + /// relative addresses, then it has a virtual address that is + /// relative to unique section in the object file. Sections get + /// resolved at runtime by DynamicLoader plug-ins as images + /// (executables and shared libraries) get loaded/unloaded. If a + /// section is loaded, then the load address can be resolved. + /// + /// @return + /// The valid load virtual address, or LLDB_INVALID_ADDRESS if + /// the address is currently not loaded. + //------------------------------------------------------------------ + lldb::addr_t GetLoadAddress(Target *target) const; + + //------------------------------------------------------------------ + /// Get the load address as a callable code load address. + /// + /// This function will first resolve its address to a load address. + /// Then, if the address turns out to be in code address, return the + /// load address that would be required to call or return to. The + /// address might have extra bits set (bit zero will be set to Thumb + /// functions for an ARM target) that are required when changing the + /// program counter to setting a return address. + /// + /// @return + /// The valid load virtual address, or LLDB_INVALID_ADDRESS if + /// the address is currently not loaded. + //------------------------------------------------------------------ + lldb::addr_t GetCallableLoadAddress(Target *target, + bool is_indirect = false) const; + + //------------------------------------------------------------------ + /// Get the load address as an opcode load address. + /// + /// This function will first resolve its address to a load address. + /// Then, if the address turns out to be in code address, return the + /// load address for an opcode. This address object might have + /// extra bits set (bit zero will be set to Thumb functions for an + /// ARM target) that are required for changing the program counter + /// and this function will remove any bits that are intended for + /// these special purposes. The result of this function can be used + /// to safely write a software breakpoint trap to memory. + /// + /// @return + /// The valid load virtual address with extra callable bits + /// removed, or LLDB_INVALID_ADDRESS if the address is currently + /// not loaded. + //------------------------------------------------------------------ + lldb::addr_t GetOpcodeLoadAddress( + Target *target, + lldb::AddressClass addr_class = lldb::eAddressClassInvalid) const; + + //------------------------------------------------------------------ + /// Get the section relative offset value. + /// + /// @return + /// The current offset, or LLDB_INVALID_ADDRESS if this address + /// doesn't contain a valid offset. + //------------------------------------------------------------------ + lldb::addr_t GetOffset() const { return m_offset; } + + //------------------------------------------------------------------ + /// Check if an address is section offset. + /// + /// When converting a virtual file or load address into a section + /// offset based address, we often need to know if, given a section + /// list, if the address was able to be converted to section offset. + /// This function returns true if the current value contained in + /// this object is section offset based. + /// + /// @return + /// Returns \b true if the address has a valid section and + /// offset, \b false otherwise. + //------------------------------------------------------------------ + bool IsSectionOffset() const { + return IsValid() && (GetSection().get() != nullptr); + } + + //------------------------------------------------------------------ + /// 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 offset is valid, \b false + /// otherwise. + //------------------------------------------------------------------ + bool IsValid() const { return m_offset != LLDB_INVALID_ADDRESS; } + + //------------------------------------------------------------------ + /// Get the memory cost of this object. + /// + /// @return + /// The number of bytes that this object occupies in memory. + //------------------------------------------------------------------ + size_t MemorySize() const; + + //------------------------------------------------------------------ + /// Resolve a file virtual address using a section list. + /// + /// Given a list of sections, attempt to resolve \a addr as a + /// an offset into one of the file sections. + /// + /// @return + /// Returns \b true if \a addr was able to be resolved, \b false + /// otherwise. + //------------------------------------------------------------------ + bool ResolveAddressUsingFileSections(lldb::addr_t addr, + const SectionList *sections); + + //------------------------------------------------------------------ + /// Set the address to represent \a load_addr. + /// + /// The address will attempt to find a loaded section within + /// \a target that contains \a load_addr. If successful, this + /// address object will have a valid section and offset. Else this + /// address object will have no section (NULL) and the offset will + /// be \a load_addr. + /// + /// @param[in] load_addr + /// A load address from a current process. + /// + /// @param[in] target + /// The target to use when trying resolve the address into + /// a section + offset. The Target's SectionLoadList object + /// is used to resolve the address. + /// + /// @param[in] allow_section_end + /// If true, treat an address pointing to the end of the module as + /// belonging to that module. + /// + /// @return + /// Returns \b true if the load address was resolved to be + /// section/offset, \b false otherwise. It is often ok for an + /// address no not resolve to a section in a module, this often + /// happens for JIT'ed code, or any load addresses on the stack + /// or heap. + //------------------------------------------------------------------ + bool SetLoadAddress(lldb::addr_t load_addr, Target *target, + bool allow_section_end = false); + + bool SetOpcodeLoadAddress( + lldb::addr_t load_addr, Target *target, + lldb::AddressClass addr_class = lldb::eAddressClassInvalid, + bool allow_section_end = false); + + bool SetCallableLoadAddress(lldb::addr_t load_addr, Target *target); + + //------------------------------------------------------------------ + /// Get accessor for the module for this address. + /// + /// @return + /// Returns the Module pointer that this address is an offset + /// in, or NULL if this address doesn't belong in a module, or + /// isn't resolved yet. + //------------------------------------------------------------------ + lldb::ModuleSP GetModule() const; + + //------------------------------------------------------------------ + /// Get const accessor for the section. + /// + /// @return + /// Returns the const lldb::Section pointer that this address is an + /// offset in, or NULL if this address is absolute. + //------------------------------------------------------------------ + lldb::SectionSP GetSection() const { return m_section_wp.lock(); } + + //------------------------------------------------------------------ + /// Set accessor for the offset. + /// + /// @param[in] offset + /// A new offset value for this object. + /// + /// @return + /// Returns \b true if the offset changed, \b false otherwise. + //------------------------------------------------------------------ + bool SetOffset(lldb::addr_t offset) { + bool changed = m_offset != offset; + m_offset = offset; + return changed; + } + + void SetRawAddress(lldb::addr_t addr) { + m_section_wp.reset(); + m_offset = addr; + } + + bool Slide(int64_t offset) { + if (m_offset != LLDB_INVALID_ADDRESS) { + m_offset += offset; + return true; + } + return false; + } + + //------------------------------------------------------------------ + /// Set accessor for the section. + /// + /// @param[in] section + /// A new lldb::Section pointer to use as the section base. Can + /// be NULL for absolute addresses that are not relative to + /// any section. + //------------------------------------------------------------------ + void SetSection(const lldb::SectionSP §ion_sp) { + m_section_wp = section_sp; + } + + void ClearSection() { m_section_wp.reset(); } + + //------------------------------------------------------------------ + /// Reconstruct a symbol context from an address. + /// + /// This class doesn't inherit from SymbolContextScope because many + /// address objects have short lifespans. Address objects that are + /// section offset can reconstruct their symbol context by looking + /// up the address in the module found in the section. + /// + /// @see SymbolContextScope::CalculateSymbolContext(SymbolContext*) + //------------------------------------------------------------------ + uint32_t CalculateSymbolContext( + SymbolContext *sc, + uint32_t resolve_scope = lldb::eSymbolContextEverything) const; + + lldb::ModuleSP CalculateSymbolContextModule() const; + + CompileUnit *CalculateSymbolContextCompileUnit() const; + + Function *CalculateSymbolContextFunction() const; + + Block *CalculateSymbolContextBlock() const; + + Symbol *CalculateSymbolContextSymbol() const; + + bool CalculateSymbolContextLineEntry(LineEntry &line_entry) const; + + //------------------------------------------------------------------ + // Returns true if the section should be valid, but isn't because + // the shared pointer to the section can't be reconstructed from + // a weak pointer that contains a valid weak reference to a section. + // Returns false if the section weak pointer has no reference to + // a section, or if the section is still valid + //------------------------------------------------------------------ + bool SectionWasDeleted() const; + +protected: + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + lldb::SectionWP m_section_wp; ///< The section for the address, can be NULL. + lldb::addr_t m_offset; ///< Offset into section if \a m_section_wp is valid... + + //------------------------------------------------------------------ + // Returns true if the m_section_wp once had a reference to a valid + // section shared pointer, but no longer does. This can happen if + // we have an address from a module that gets unloaded and deleted. + // This function should only be called if GetSection() returns an + // empty shared pointer and you want to know if this address used to + // have a valid section. + //------------------------------------------------------------------ + bool SectionWasDeletedPrivate() const; +}; + +//---------------------------------------------------------------------- +// NOTE: Be careful using this operator. It can correctly compare two +// addresses from the same Module correctly. It can't compare two +// addresses from different modules in any meaningful way, but it will +// compare the module pointers. +// +// To sum things up: +// - works great for addresses within the same module +// - it works for addresses across multiple modules, but don't expect the +// address results to make much sense +// +// This basically lets Address objects be used in ordered collection +// classes. +//---------------------------------------------------------------------- +bool operator<(const Address &lhs, const Address &rhs); +bool operator>(const Address &lhs, const Address &rhs); +bool operator==(const Address &lhs, const Address &rhs); +bool operator!=(const Address &lhs, const Address &rhs); + +} // namespace lldb_private + +#endif // liblldb_Address_h_ diff --git a/include/lldb/Core/AddressRange.h b/include/lldb/Core/AddressRange.h new file mode 100644 index 000000000..e787d1d57 --- /dev/null +++ b/include/lldb/Core/AddressRange.h @@ -0,0 +1,289 @@ +//===-- 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" +#include "lldb/lldb-forward.h" // for SectionSP +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t + +namespace lldb_private { +class SectionList; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class Target; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class AddressRange AddressRange.h "lldb/Core/AddressRange.h" +/// @brief A section + offset based address range class. +//---------------------------------------------------------------------- +class AddressRange { +public: + //------------------------------------------------------------------ + /// Default constructor. + /// + /// Initialize with a invalid section (NULL), an invalid + /// offset (LLDB_INVALID_ADDRESS), and zero byte size. + //------------------------------------------------------------------ + AddressRange(); + + //------------------------------------------------------------------ + /// Construct with a section pointer, offset, and byte_size. + /// + /// Initialize the address with the supplied \a section, \a + /// offset and \a byte_size. + /// + /// @param[in] section + /// A section pointer to a valid lldb::Section, or NULL if the + /// address doesn't have a section or will get resolved later. + /// + /// @param[in] offset + /// The offset in bytes into \a section. + /// + /// @param[in] byte_size + /// The size in bytes of the address range. + //------------------------------------------------------------------ + AddressRange(const lldb::SectionSP §ion, 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 = nullptr); + + //------------------------------------------------------------------ + /// Construct with a Address object address and byte size. + /// + /// Initialize by copying the section offset address in \a so_addr, + /// and setting the byte size to \a byte_size. + /// + /// @param[in] so_addr + /// A section offset address object. + /// + /// @param[in] byte_size + /// The size in bytes of the address range. + //------------------------------------------------------------------ + AddressRange(const Address &so_addr, lldb::addr_t byte_size); + + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual in case this class is subclassed. + //------------------------------------------------------------------ + ~AddressRange(); + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Sets the section to an invalid value (NULL), an invalid offset + /// (LLDB_INVALID_ADDRESS) and a zero byte size. + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + /// Check if a section offset address is contained in this range. + /// + /// @param[in] so_addr + /// A section offset address object reference. + /// + /// @return + /// Returns \b true if \a so_addr is contained in this range, + /// \b false otherwise. + //------------------------------------------------------------------ + // bool + // Contains (const Address &so_addr) const; + + //------------------------------------------------------------------ + /// Check if a section offset address is contained in this range. + /// + /// @param[in] so_addr_ptr + /// A section offset address object pointer. + /// + /// @return + /// Returns \b true if \a so_addr is contained in this range, + /// \b false otherwise. + //------------------------------------------------------------------ + // bool + // Contains (const Address *so_addr_ptr) const; + + //------------------------------------------------------------------ + /// Check if a section offset \a so_addr when represented as a file + /// address is contained within this object's file address range. + /// + /// @param[in] so_addr + /// A section offset address object reference. + /// + /// @return + /// Returns \b true if both \a this and \a so_addr have + /// resolvable file address values and \a so_addr is contained + /// in the address range, \b false otherwise. + //------------------------------------------------------------------ + bool ContainsFileAddress(const Address &so_addr) const; + + //------------------------------------------------------------------ + /// Check if the resolved file address \a file_addr is contained + /// within this object's file address range. + /// + /// @param[in] so_addr + /// A section offset address object reference. + /// + /// @return + /// Returns \b true if both \a this has a resolvable file + /// address value and \a so_addr is contained in the address + /// range, \b false otherwise. + //------------------------------------------------------------------ + bool ContainsFileAddress(lldb::addr_t file_addr) const; + + //------------------------------------------------------------------ + /// Check if a section offset \a so_addr when represented as a load + /// address is contained within this object's load address range. + /// + /// @param[in] so_addr + /// A section offset address object reference. + /// + /// @return + /// Returns \b true if both \a this and \a so_addr have + /// resolvable load address values and \a so_addr is contained + /// in the address range, \b false otherwise. + //------------------------------------------------------------------ + bool ContainsLoadAddress(const Address &so_addr, Target *target) const; + + //------------------------------------------------------------------ + /// Check if the resolved load address \a load_addr is contained + /// within this object's load address range. + /// + /// @param[in] so_addr + /// A section offset address object reference. + /// + /// @return + /// Returns \b true if both \a this has a resolvable load + /// address value and \a so_addr is contained in the address + /// range, \b false otherwise. + //------------------------------------------------------------------ + bool ContainsLoadAddress(lldb::addr_t load_addr, Target *target) const; + + //------------------------------------------------------------------ + /// Dump a description of this object to a Stream. + /// + /// Dump a description of the contents of this object to the + /// supplied stream \a s. There are many ways to display a section + /// offset based address range, and \a style lets the user choose + /// how the base address gets displayed. + /// + /// @param[in] s + /// The stream to which to dump the object description. + /// + /// @param[in] style + /// The display style for the address. + /// + /// @return + /// Returns \b true if the address was able to be displayed. + /// File and load addresses may be unresolved and it may not be + /// possible to display a valid value, \b false will be returned + /// in such cases. + /// + /// @see Address::DumpStyle + //------------------------------------------------------------------ + bool + Dump(Stream *s, Target *target, Address::DumpStyle style, + Address::DumpStyle fallback_style = Address::DumpStyleInvalid) const; + + //------------------------------------------------------------------ + /// Dump a debug description of this object to a Stream. + /// + /// Dump a debug description of the contents of this object to the + /// supplied stream \a s. + /// + /// The debug description contains verbose internal state such + /// and pointer values, reference counts, etc. + /// + /// @param[in] s + /// The stream to which to dump the object description. + //------------------------------------------------------------------ + void DumpDebug(Stream *s) const; + + //------------------------------------------------------------------ + /// Get accessor for the base address of the range. + /// + /// @return + /// A reference to the base address object. + //------------------------------------------------------------------ + Address &GetBaseAddress() { return m_base_addr; } + + //------------------------------------------------------------------ + /// Get const accessor for the base address of the range. + /// + /// @return + /// A const reference to the base address object. + //------------------------------------------------------------------ + const Address &GetBaseAddress() const { return m_base_addr; } + + //------------------------------------------------------------------ + /// Get accessor for the byte size of this range. + /// + /// @return + /// The size in bytes of this address range. + //------------------------------------------------------------------ + lldb::addr_t GetByteSize() const { return m_byte_size; } + + //------------------------------------------------------------------ + /// Get the memory cost of this object. + /// + /// @return + /// The number of bytes that this object occupies in memory. + //------------------------------------------------------------------ + size_t MemorySize() const { + // Noting special for the memory size of a single AddressRange object, + // it is just the size of itself. + return sizeof(AddressRange); + } + + //------------------------------------------------------------------ + /// Set accessor for the byte size of this range. + /// + /// @param[in] byte_size + /// The new size in bytes of this address range. + //------------------------------------------------------------------ + void SetByteSize(lldb::addr_t byte_size) { m_byte_size = byte_size; } + +protected: + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + Address m_base_addr; ///< The section offset base address of this range. + lldb::addr_t m_byte_size; ///< The size in bytes of this address range. +}; + +// bool operator== (const AddressRange& lhs, const AddressRange& rhs); + +} // namespace lldb_private + +#endif // liblldb_AddressRange_h_ diff --git a/include/lldb/Core/AddressResolver.h b/include/lldb/Core/AddressResolver.h new file mode 100644 index 000000000..432268e49 --- /dev/null +++ b/include/lldb/Core/AddressResolver.h @@ -0,0 +1,74 @@ +//===-- 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 "lldb/Core/AddressRange.h" +#include "lldb/Core/SearchFilter.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN + +#include // for size_t +#include + +namespace lldb_private { +class ModuleList; +} +namespace lldb_private { +class Stream; +} +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(); + + ~AddressResolver() override; + + virtual void ResolveAddress(SearchFilter &filter); + + virtual void ResolveAddressInModules(SearchFilter &filter, + ModuleList &modules); + + void GetDescription(Stream *s) override = 0; + + std::vector &GetAddressRanges(); + + size_t GetNumberOfAddresses(); + + AddressRange &GetAddressRangeAtIndex(size_t idx); + +protected: + std::vector m_address_ranges; + +private: + DISALLOW_COPY_AND_ASSIGN(AddressResolver); +}; + +} // namespace lldb_private + +#endif // liblldb_AddressResolver_h_ diff --git a/include/lldb/Core/AddressResolverFileLine.h b/include/lldb/Core/AddressResolverFileLine.h new file mode 100644 index 000000000..ec15cc76d --- /dev/null +++ b/include/lldb/Core/AddressResolverFileLine.h @@ -0,0 +1,67 @@ +//===-- 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_ + +#include "lldb/Core/AddressResolver.h" +#include "lldb/Core/SearchFilter.h" // for Searcher, Searcher::CallbackR... +#include "lldb/Utility/FileSpec.h" // for FileSpec +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN + +#include // for uint32_t + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContext; +} + +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); + + ~AddressResolverFileLine() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + +protected: + FileSpec m_file_spec; // This is the file spec we are looking for. + uint32_t m_line_number; // This is the line number that we are looking for. + bool m_inlines; // This determines whether the resolver looks for inlined + // functions or not. + +private: + DISALLOW_COPY_AND_ASSIGN(AddressResolverFileLine); +}; + +} // namespace lldb_private + +#endif // liblldb_AddressResolverFileLine_h_ diff --git a/include/lldb/Core/AddressResolverName.h b/include/lldb/Core/AddressResolverName.h new file mode 100644 index 000000000..aadc05495 --- /dev/null +++ b/include/lldb/Core/AddressResolverName.h @@ -0,0 +1,74 @@ +//===-- 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_ + +#include "lldb/Core/AddressResolver.h" +#include "lldb/Core/SearchFilter.h" // for Searcher, Searcher::Call... +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/RegularExpression.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContext; +} + +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); + + ~AddressResolverName() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + +protected: + ConstString m_func_name; + ConstString m_class_name; // FIXME: Not used yet. The idea would be to stop + // on methods of this class. + RegularExpression m_regex; + AddressResolver::MatchType m_match_type; + +private: + DISALLOW_COPY_AND_ASSIGN(AddressResolverName); +}; + +} // namespace lldb_private + +#endif // liblldb_AddressResolverName_h_ diff --git a/include/lldb/Core/ArchSpec.h b/include/lldb/Core/ArchSpec.h new file mode 100644 index 000000000..75c7079be --- /dev/null +++ b/include/lldb/Core/ArchSpec.h @@ -0,0 +1,665 @@ +//===-- 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/Utility/ConstString.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private-enumerations.h" +#include "llvm/ADT/StringRef.h" // for StringRef +#include "llvm/ADT/Triple.h" + +#include // for string + +#include // for size_t +#include // for uint32_t + +namespace lldb_private { +class Platform; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class StringList; +} +namespace lldb_private { +class Thread; +} + +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, a +/// string representation, or an llvm::Triple. Keeping all of the +/// conversions of strings to architecture enumeration values confined +/// to this class allows new architecture support to be added easily. +//---------------------------------------------------------------------- +class ArchSpec { +public: + enum MIPSSubType { + eMIPSSubType_unknown, + eMIPSSubType_mips32, + eMIPSSubType_mips32r2, + eMIPSSubType_mips32r6, + eMIPSSubType_mips32el, + eMIPSSubType_mips32r2el, + eMIPSSubType_mips32r6el, + eMIPSSubType_mips64, + eMIPSSubType_mips64r2, + eMIPSSubType_mips64r6, + eMIPSSubType_mips64el, + eMIPSSubType_mips64r2el, + eMIPSSubType_mips64r6el, + }; + + // Masks for the ases word of an ABI flags structure. + enum MIPSASE { + eMIPSAse_dsp = 0x00000001, // DSP ASE + eMIPSAse_dspr2 = 0x00000002, // DSP R2 ASE + eMIPSAse_eva = 0x00000004, // Enhanced VA Scheme + eMIPSAse_mcu = 0x00000008, // MCU (MicroController) ASE + eMIPSAse_mdmx = 0x00000010, // MDMX ASE + eMIPSAse_mips3d = 0x00000020, // MIPS-3D ASE + eMIPSAse_mt = 0x00000040, // MT ASE + eMIPSAse_smartmips = 0x00000080, // SmartMIPS ASE + eMIPSAse_virt = 0x00000100, // VZ ASE + eMIPSAse_msa = 0x00000200, // MSA ASE + eMIPSAse_mips16 = 0x00000400, // MIPS16 ASE + eMIPSAse_micromips = 0x00000800, // MICROMIPS ASE + eMIPSAse_xpa = 0x00001000, // XPA ASE + eMIPSAse_mask = 0x00001fff, + eMIPSABI_O32 = 0x00002000, + eMIPSABI_N32 = 0x00004000, + eMIPSABI_N64 = 0x00008000, + eMIPSABI_O64 = 0x00020000, + eMIPSABI_EABI32 = 0x00040000, + eMIPSABI_EABI64 = 0x00080000, + eMIPSABI_mask = 0x000ff000 + }; + + // MIPS Floating point ABI Values + enum MIPS_ABI_FP { + eMIPS_ABI_FP_ANY = 0x00000000, + eMIPS_ABI_FP_DOUBLE = 0x00100000, // hard float / -mdouble-float + eMIPS_ABI_FP_SINGLE = 0x00200000, // hard float / -msingle-float + eMIPS_ABI_FP_SOFT = 0x00300000, // soft float + eMIPS_ABI_FP_OLD_64 = 0x00400000, // -mips32r2 -mfp64 + eMIPS_ABI_FP_XX = 0x00500000, // -mfpxx + eMIPS_ABI_FP_64 = 0x00600000, // -mips32r2 -mfp64 + eMIPS_ABI_FP_64A = 0x00700000, // -mips32r2 -mfp64 -mno-odd-spreg + eMIPS_ABI_FP_mask = 0x00700000 + }; + + // ARM specific e_flags + enum ARMeflags { + eARM_abi_soft_float = 0x00000200, + eARM_abi_hard_float = 0x00000400 + }; + + enum Core { + eCore_arm_generic, + eCore_arm_armv4, + eCore_arm_armv4t, + eCore_arm_armv5, + eCore_arm_armv5e, + eCore_arm_armv5t, + eCore_arm_armv6, + eCore_arm_armv6m, + eCore_arm_armv7, + eCore_arm_armv7f, + eCore_arm_armv7s, + eCore_arm_armv7k, + eCore_arm_armv7m, + eCore_arm_armv7em, + eCore_arm_xscale, + + eCore_thumb, + eCore_thumbv4t, + eCore_thumbv5, + eCore_thumbv5e, + eCore_thumbv6, + eCore_thumbv6m, + eCore_thumbv7, + eCore_thumbv7s, + eCore_thumbv7k, + eCore_thumbv7f, + eCore_thumbv7m, + eCore_thumbv7em, + eCore_arm_arm64, + eCore_arm_armv8, + eCore_arm_aarch64, + + eCore_mips32, + eCore_mips32r2, + eCore_mips32r3, + eCore_mips32r5, + eCore_mips32r6, + eCore_mips32el, + eCore_mips32r2el, + eCore_mips32r3el, + eCore_mips32r5el, + eCore_mips32r6el, + eCore_mips64, + eCore_mips64r2, + eCore_mips64r3, + eCore_mips64r5, + eCore_mips64r6, + eCore_mips64el, + eCore_mips64r2el, + eCore_mips64r3el, + eCore_mips64r5el, + eCore_mips64r6el, + + eCore_ppc_generic, + eCore_ppc_ppc601, + eCore_ppc_ppc602, + eCore_ppc_ppc603, + eCore_ppc_ppc603e, + eCore_ppc_ppc603ev, + eCore_ppc_ppc604, + eCore_ppc_ppc604e, + eCore_ppc_ppc620, + eCore_ppc_ppc750, + eCore_ppc_ppc7400, + eCore_ppc_ppc7450, + eCore_ppc_ppc970, + + eCore_ppc64_generic, + eCore_ppc64_ppc970_64, + + eCore_s390x_generic, + + eCore_sparc_generic, + + eCore_sparc9_generic, + + eCore_x86_32_i386, + eCore_x86_32_i486, + eCore_x86_32_i486sx, + eCore_x86_32_i686, + + eCore_x86_64_x86_64, + eCore_x86_64_x86_64h, // Haswell enabled x86_64 + eCore_hexagon_generic, + eCore_hexagon_hexagonv4, + eCore_hexagon_hexagonv5, + + eCore_uknownMach32, + eCore_uknownMach64, + + eCore_kalimba3, + eCore_kalimba4, + eCore_kalimba5, + + kNumCores, + + kCore_invalid, + // The following constants are used for wildcard matching only + kCore_any, + kCore_arm_any, + kCore_ppc_any, + kCore_ppc64_any, + kCore_x86_32_any, + kCore_x86_64_any, + kCore_hexagon_any, + + kCore_arm_first = eCore_arm_generic, + kCore_arm_last = eCore_arm_xscale, + + kCore_thumb_first = eCore_thumb, + kCore_thumb_last = eCore_thumbv7em, + + kCore_ppc_first = eCore_ppc_generic, + kCore_ppc_last = eCore_ppc_ppc970, + + kCore_ppc64_first = eCore_ppc64_generic, + kCore_ppc64_last = eCore_ppc64_ppc970_64, + + kCore_x86_32_first = eCore_x86_32_i386, + kCore_x86_32_last = eCore_x86_32_i686, + + kCore_x86_64_first = eCore_x86_64_x86_64, + kCore_x86_64_last = eCore_x86_64_x86_64h, + + kCore_hexagon_first = eCore_hexagon_generic, + kCore_hexagon_last = eCore_hexagon_hexagonv5, + + kCore_kalimba_first = eCore_kalimba3, + kCore_kalimba_last = eCore_kalimba5, + + kCore_mips32_first = eCore_mips32, + kCore_mips32_last = eCore_mips32r6, + + kCore_mips32el_first = eCore_mips32el, + kCore_mips32el_last = eCore_mips32r6el, + + kCore_mips64_first = eCore_mips64, + kCore_mips64_last = eCore_mips64r6, + + kCore_mips64el_first = eCore_mips64el, + kCore_mips64el_last = eCore_mips64r6el, + + kCore_mips_first = eCore_mips32, + kCore_mips_last = eCore_mips64r6el + + }; + + typedef void (*StopInfoOverrideCallbackType)(lldb_private::Thread &thread); + + //------------------------------------------------------------------ + /// Default constructor. + /// + /// Default constructor that initializes the object with invalid + /// cpu type and subtype values. + //------------------------------------------------------------------ + ArchSpec(); + + //------------------------------------------------------------------ + /// Constructor over triple. + /// + /// Constructs an ArchSpec with properties consistent with the given + /// Triple. + //------------------------------------------------------------------ + explicit ArchSpec(const llvm::Triple &triple); + explicit ArchSpec(const char *triple_cstr); + explicit ArchSpec(llvm::StringRef triple_str); + ArchSpec(const char *triple_cstr, Platform *platform); + ArchSpec(llvm::StringRef triple_str, Platform *platform); + //------------------------------------------------------------------ + /// Constructor over architecture name. + /// + /// Constructs an ArchSpec with properties consistent with the given + /// object type and architecture name. + //------------------------------------------------------------------ + explicit ArchSpec(ArchitectureType arch_type, uint32_t cpu_type, + uint32_t cpu_subtype); + + //------------------------------------------------------------------ + /// Destructor. + //------------------------------------------------------------------ + ~ArchSpec(); + + //------------------------------------------------------------------ + /// Assignment operator. + /// + /// @param[in] rhs another ArchSpec object to copy. + /// + /// @return A const reference to this object. + //------------------------------------------------------------------ + const ArchSpec &operator=(const ArchSpec &rhs); + + static size_t AutoComplete(llvm::StringRef name, StringList &matches); + + //------------------------------------------------------------------ + /// Returns a static string representing the current architecture. + /// + /// @return A static string correcponding to the current + /// architecture. + //------------------------------------------------------------------ + const char *GetArchitectureName() const; + + //----------------------------------------------------------------- + /// if MIPS architecture return true. + /// + /// @return a boolean value. + //----------------------------------------------------------------- + bool IsMIPS() const; + + //------------------------------------------------------------------ + /// Returns a string representing current architecture as a target CPU + /// for tools like compiler, disassembler etc. + /// + /// @return A string representing target CPU for the current + /// architecture. + //------------------------------------------------------------------ + std::string GetClangTargetCPU() const; + + //------------------------------------------------------------------ + /// Return a string representing target application ABI. + /// + /// @return A string representing target application ABI. + //------------------------------------------------------------------ + std::string GetTargetABI() const; + + //------------------------------------------------------------------ + /// Clears the object state. + /// + /// Clears the object state back to a default invalid state. + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + /// Returns the size in bytes of an address of the current + /// architecture. + /// + /// @return The byte size of an address of the current architecture. + //------------------------------------------------------------------ + uint32_t GetAddressByteSize() const; + + //------------------------------------------------------------------ + /// Returns a machine family for the current architecture. + /// + /// @return An LLVM arch type. + //------------------------------------------------------------------ + llvm::Triple::ArchType GetMachine() const; + + //------------------------------------------------------------------ + /// Returns the distribution id of the architecture. + /// + /// This will be something like "ubuntu", "fedora", etc. on Linux. + /// + /// @return A ConstString ref containing the distribution id, + /// potentially empty. + //------------------------------------------------------------------ + const ConstString &GetDistributionId() const; + + //------------------------------------------------------------------ + /// Set the distribution id of the architecture. + /// + /// This will be something like "ubuntu", "fedora", etc. on Linux. + /// This should be the same value returned by + /// HostInfo::GetDistributionId (). + ///------------------------------------------------------------------ + void SetDistributionId(const char *distribution_id); + + //------------------------------------------------------------------ + /// Tests if this ArchSpec is valid. + /// + /// @return True if the current architecture is valid, false + /// otherwise. + //------------------------------------------------------------------ + bool IsValid() const { + return m_core >= eCore_arm_generic && m_core < kNumCores; + } + + bool TripleVendorWasSpecified() const { + return !m_triple.getVendorName().empty(); + } + + bool TripleVendorIsUnspecifiedUnknown() const { + return m_triple.getVendor() == llvm::Triple::UnknownVendor && + m_triple.getVendorName().empty(); + } + + bool TripleOSWasSpecified() const { return !m_triple.getOSName().empty(); } + + bool TripleEnvironmentWasSpecified() const { + return !m_triple.getEnvironmentName().empty(); + } + + bool TripleOSIsUnspecifiedUnknown() const { + return m_triple.getOS() == llvm::Triple::UnknownOS && + m_triple.getOSName().empty(); + } + + //------------------------------------------------------------------ + /// Merges fields from another ArchSpec into this ArchSpec. + /// + /// This will use the supplied ArchSpec to fill in any fields of + /// the triple in this ArchSpec which were unspecified. This can + /// be used to refine a generic ArchSpec with a more specific one. + /// For example, if this ArchSpec's triple is something like + /// i386-unknown-unknown-unknown, and we have a triple which is + /// x64-pc-windows-msvc, then merging that triple into this one + /// will result in the triple i386-pc-windows-msvc. + /// + //------------------------------------------------------------------ + void MergeFrom(const ArchSpec &other); + + //------------------------------------------------------------------ + /// Change the architecture object type, CPU type and OS type. + /// + /// @param[in] arch_type The object type of this ArchSpec. + /// + /// @param[in] cpu The required CPU type. + /// + /// @param[in] os The optional OS type + /// The default value of 0 was chosen to from the ELF spec value + /// ELFOSABI_NONE. ELF is the only one using this parameter. If another + /// format uses this parameter and 0 does not work, use a value over + /// 255 because in the ELF header this is value is only a byte. + /// + /// @return True if the object, and CPU were successfully set. + /// + /// As a side effect, the vendor value is usually set to unknown. + /// The exections are + /// aarch64-apple-ios + /// arm-apple-ios + /// thumb-apple-ios + /// x86-apple- + /// x86_64-apple- + /// + /// As a side effect, the os value is usually set to unknown + /// The exceptions are + /// *-*-aix + /// aarch64-apple-ios + /// arm-apple-ios + /// thumb-apple-ios + /// powerpc-apple-darwin + /// *-*-freebsd + /// *-*-linux + /// *-*-netbsd + /// *-*-openbsd + /// *-*-solaris + //------------------------------------------------------------------ + bool SetArchitecture(ArchitectureType arch_type, uint32_t cpu, uint32_t sub, + uint32_t os = 0); + + //------------------------------------------------------------------ + /// Returns the byte order for the architecture specification. + /// + /// @return The endian enumeration for the current endianness of + /// the architecture specification + //------------------------------------------------------------------ + lldb::ByteOrder GetByteOrder() const; + + //------------------------------------------------------------------ + /// Sets this ArchSpec's byte order. + /// + /// In the common case there is no need to call this method as the + /// byte order can almost always be determined by the architecture. + /// However, many CPU's are bi-endian (ARM, Alpha, PowerPC, etc) + /// and the default/assumed byte order may be incorrect. + //------------------------------------------------------------------ + void SetByteOrder(lldb::ByteOrder byte_order) { m_byte_order = byte_order; } + + uint32_t GetMinimumOpcodeByteSize() const; + + uint32_t GetMaximumOpcodeByteSize() const; + + Core GetCore() const { return m_core; } + + uint32_t GetMachOCPUType() const; + + uint32_t GetMachOCPUSubType() const; + + //------------------------------------------------------------------ + /// Architecture data byte width accessor + /// + /// @return the size in 8-bit (host) bytes of a minimum addressable + /// unit from the Architecture's data bus + //------------------------------------------------------------------ + uint32_t GetDataByteSize() const; + + //------------------------------------------------------------------ + /// Architecture code byte width accessor + /// + /// @return the size in 8-bit (host) bytes of a minimum addressable + /// unit from the Architecture's code bus + //------------------------------------------------------------------ + uint32_t GetCodeByteSize() const; + + //------------------------------------------------------------------ + /// Architecture tripple accessor. + /// + /// @return A triple describing this ArchSpec. + //------------------------------------------------------------------ + llvm::Triple &GetTriple() { return m_triple; } + + //------------------------------------------------------------------ + /// Architecture tripple accessor. + /// + /// @return A triple describing this ArchSpec. + //------------------------------------------------------------------ + const llvm::Triple &GetTriple() const { return m_triple; } + + void DumpTriple(Stream &s) const; + + //------------------------------------------------------------------ + /// Architecture tripple setter. + /// + /// Configures this ArchSpec according to the given triple. If the + /// triple has unknown components in all of the vendor, OS, and + /// the optional environment field (i.e. "i386-unknown-unknown") + /// then default values are taken from the host. Architecture and + /// environment components are used to further resolve the CPU type + /// and subtype, endian characteristics, etc. + /// + /// @return A triple describing this ArchSpec. + //------------------------------------------------------------------ + bool SetTriple(const llvm::Triple &triple); + + bool SetTriple(llvm::StringRef triple_str); + bool SetTriple(llvm::StringRef triple_str, Platform *platform); + + bool SetTriple(const char *triple_cstr); + bool SetTriple(const char *triple_cstr, Platform *platform); + + //------------------------------------------------------------------ + /// Returns the default endianness of the architecture. + /// + /// @return The endian enumeration for the default endianness of + /// the architecture. + //------------------------------------------------------------------ + lldb::ByteOrder GetDefaultEndian() const; + + //------------------------------------------------------------------ + /// Returns true if 'char' is a signed type by defualt in the + /// architecture false otherwise + /// + /// @return True if 'char' is a signed type by default on the + /// architecture and false otherwise. + //------------------------------------------------------------------ + bool CharIsSignedByDefault() const; + + //------------------------------------------------------------------ + /// Compare an ArchSpec to another ArchSpec, requiring an exact cpu + /// type match between them. + /// e.g. armv7s is not an exact match with armv7 - this would return false + /// + /// @return true if the two ArchSpecs match. + //------------------------------------------------------------------ + bool IsExactMatch(const ArchSpec &rhs) const; + + //------------------------------------------------------------------ + /// Compare an ArchSpec to another ArchSpec, requiring a compatible + /// cpu type match between them. + /// e.g. armv7s is compatible with armv7 - this method would return true + /// + /// @return true if the two ArchSpecs are compatible + //------------------------------------------------------------------ + bool IsCompatibleMatch(const ArchSpec &rhs) const; + + //------------------------------------------------------------------ + /// Get a stop info override callback for the current architecture. + /// + /// Most platform specific code should go in lldb_private::Platform, + /// but there are cases where no matter which platform you are on + /// certain things hold true. + /// + /// This callback is currently intended to handle cases where a + /// program stops at an instruction that won't get executed and it + /// allows the stop reasonm, like "breakpoint hit", to be replaced + /// with a different stop reason like "no stop reason". + /// + /// This is specifically used for ARM in Thumb code when we stop in + /// an IT instruction (if/then/else) where the instruction won't get + /// executed and therefore it wouldn't be correct to show the program + /// stopped at the current PC. The code is generic and applies to all + /// ARM CPUs. + /// + /// @return NULL or a valid stop info override callback for the + /// current architecture. + //------------------------------------------------------------------ + StopInfoOverrideCallbackType GetStopInfoOverrideCallback() const; + + bool IsFullySpecifiedTriple() const; + + void PiecewiseTripleCompare(const ArchSpec &other, bool &arch_different, + bool &vendor_different, bool &os_different, + bool &os_version_different, bool &env_different); + + //------------------------------------------------------------------ + /// Detect whether this architecture uses thumb code exclusively + /// + /// Some embedded ARM chips (e.g. the ARM Cortex M0-7 line) can + /// only execute the Thumb instructions, never Arm. We should normally + /// pick up arm/thumbness from their the processor status bits (cpsr/xpsr) + /// or hints on each function - but when doing bare-boards low level + /// debugging (especially common with these embedded processors), we may + /// not have those things easily accessible. + /// + /// @return true if this is an arm ArchSpec which can only execute Thumb + /// instructions + //------------------------------------------------------------------ + bool IsAlwaysThumbInstructions() const; + + uint32_t GetFlags() const { return m_flags; } + + void SetFlags(uint32_t flags) { m_flags = flags; } + + void SetFlags(std::string elf_abi); + +protected: + bool IsEqualTo(const ArchSpec &rhs, bool exact_match) const; + void UpdateCore(); + + llvm::Triple m_triple; + Core m_core = kCore_invalid; + lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid; + + // Additional arch flags which we cannot get from triple and core + // For MIPS these are application specific extensions like + // micromips, mips16 etc. + uint32_t m_flags = 0; + + ConstString m_distribution_id; + + // Called when m_def or m_entry are changed. Fills in all remaining + // members with default values. + void CoreUpdated(bool update_triple); +}; + +//------------------------------------------------------------------ +/// @fn bool operator< (const ArchSpec& lhs, const ArchSpec& rhs) +/// @brief Less than operator. +/// +/// Tests two ArchSpec objects to see if \a lhs is less than \a +/// rhs. +/// +/// @param[in] lhs The Left Hand Side ArchSpec object to compare. +/// @param[in] rhs The Left Hand Side ArchSpec object to compare. +/// +/// @return true if \a lhs is less than \a rhs +//------------------------------------------------------------------ +bool operator<(const ArchSpec &lhs, const ArchSpec &rhs); + +bool ParseMachCPUDashSubtypeTriple(llvm::StringRef triple_str, ArchSpec &arch); + +} // namespace lldb_private + +#endif // #if defined(__cplusplus) +#endif // #ifndef liblldb_ArchSpec_h_ diff --git a/include/lldb/Core/Broadcaster.h b/include/lldb/Core/Broadcaster.h new file mode 100644 index 000000000..825287db5 --- /dev/null +++ b/include/lldb/Core/Broadcaster.h @@ -0,0 +1,607 @@ +//===-- 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_ + +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-forward.h" // for ListenerSP, EventSP, Broadcast... + +#include "llvm/ADT/SmallVector.h" + +#include // for uint32_t, UINT32_MAX +#include +#include // for shared_ptr, operator==, enable... +#include +#include // for set +#include +#include // for pair +#include + +namespace lldb_private { +class Broadcaster; +} +namespace lldb_private { +class EventData; +} +namespace lldb_private { +class Listener; +} +namespace lldb_private { +class Stream; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// lldb::BroadcastEventSpec +// +// This class is used to specify a kind of event to register for. The Debugger +// maintains a list of BroadcastEventSpec's and when it is made +//---------------------------------------------------------------------- +class BroadcastEventSpec { +public: + BroadcastEventSpec(const ConstString &broadcaster_class, uint32_t event_bits) + : m_broadcaster_class(broadcaster_class), m_event_bits(event_bits) {} + + BroadcastEventSpec(const BroadcastEventSpec &rhs); + + ~BroadcastEventSpec() = default; + + const ConstString &GetBroadcasterClass() const { return m_broadcaster_class; } + + uint32_t GetEventBits() const { return m_event_bits; } + + // Tell whether this BroadcastEventSpec is contained in in_spec. + // That is: + // (a) the two spec's share the same broadcaster class + // (b) the event bits of this spec are wholly contained in those of in_spec. + bool IsContainedIn(BroadcastEventSpec in_spec) const { + if (m_broadcaster_class != in_spec.GetBroadcasterClass()) + return false; + uint32_t in_bits = in_spec.GetEventBits(); + if (in_bits == m_event_bits) + return true; + else { + if ((m_event_bits & in_bits) != 0 && (m_event_bits & ~in_bits) == 0) + return true; + } + return false; + } + + bool operator<(const BroadcastEventSpec &rhs) const; + BroadcastEventSpec &operator=(const BroadcastEventSpec &rhs); + +private: + ConstString m_broadcaster_class; + uint32_t m_event_bits; +}; + +class BroadcasterManager + : public std::enable_shared_from_this { +public: + friend class Listener; + +protected: + BroadcasterManager(); + +public: + // Listeners hold onto weak pointers to their broadcaster managers. So they + // must be made into shared pointers, which you do with + // MakeBroadcasterManager. + + static lldb::BroadcasterManagerSP MakeBroadcasterManager(); + + ~BroadcasterManager() = default; + + uint32_t RegisterListenerForEvents(const lldb::ListenerSP &listener_sp, + BroadcastEventSpec event_spec); + + bool UnregisterListenerForEvents(const lldb::ListenerSP &listener_sp, + BroadcastEventSpec event_spec); + + lldb::ListenerSP GetListenerForEventSpec(BroadcastEventSpec event_spec) const; + + void SignUpListenersForBroadcaster(Broadcaster &broadcaster); + + void RemoveListener(const lldb::ListenerSP &listener_sp); + + void RemoveListener(Listener *listener); + + void Clear(); + +private: + typedef std::pair event_listener_key; + typedef std::map collection; + typedef std::set listener_collection; + collection m_event_map; + listener_collection m_listeners; + + mutable std::recursive_mutex m_manager_mutex; + + // A couple of comparator classes for find_if: + + class BroadcasterClassMatches { + public: + BroadcasterClassMatches(const ConstString &broadcaster_class) + : m_broadcaster_class(broadcaster_class) {} + + ~BroadcasterClassMatches() = default; + + bool operator()(const event_listener_key input) const { + return (input.first.GetBroadcasterClass() == m_broadcaster_class); + } + + private: + ConstString m_broadcaster_class; + }; + + class BroadcastEventSpecMatches { + public: + BroadcastEventSpecMatches(BroadcastEventSpec broadcaster_spec) + : m_broadcaster_spec(broadcaster_spec) {} + + ~BroadcastEventSpecMatches() = default; + + bool operator()(const event_listener_key input) const { + return (input.first.IsContainedIn(m_broadcaster_spec)); + } + + private: + BroadcastEventSpec m_broadcaster_spec; + }; + + class ListenerMatchesAndSharedBits { + public: + explicit ListenerMatchesAndSharedBits(BroadcastEventSpec broadcaster_spec, + const lldb::ListenerSP listener_sp) + : m_broadcaster_spec(broadcaster_spec), m_listener_sp(listener_sp) {} + + ~ListenerMatchesAndSharedBits() = default; + + bool operator()(const event_listener_key input) const { + return (input.first.GetBroadcasterClass() == + m_broadcaster_spec.GetBroadcasterClass() && + (input.first.GetEventBits() & + m_broadcaster_spec.GetEventBits()) != 0 && + input.second == m_listener_sp); + } + + private: + BroadcastEventSpec m_broadcaster_spec; + const lldb::ListenerSP m_listener_sp; + }; + + class ListenerMatches { + public: + explicit ListenerMatches(const lldb::ListenerSP in_listener_sp) + : m_listener_sp(in_listener_sp) {} + + ~ListenerMatches() = default; + + bool operator()(const event_listener_key input) const { + if (input.second == m_listener_sp) + return true; + else + return false; + } + + private: + const lldb::ListenerSP m_listener_sp; + }; + + class ListenerMatchesPointer { + public: + ListenerMatchesPointer(const Listener *in_listener) + : m_listener(in_listener) {} + + ~ListenerMatchesPointer() = default; + + bool operator()(const event_listener_key input) const { + if (input.second.get() == m_listener) + return true; + else + return false; + } + + bool operator()(const lldb::ListenerSP input) const { + if (input.get() == m_listener) + return true; + else + return false; + } + + private: + const Listener *m_listener; + }; +}; + +//---------------------------------------------------------------------- +/// @class Broadcaster Broadcaster.h "lldb/Core/Broadcaster.h" +/// @brief An event broadcasting class. +/// +/// The Broadcaster class is designed to be subclassed by objects that +/// wish to vend events in a multi-threaded environment. Broadcaster +/// objects can each vend 32 events. Each event is represented by a bit +/// in a 32 bit value and these bits can be set: +/// @see Broadcaster::SetEventBits(uint32_t) +/// or cleared: +/// @see Broadcaster::ResetEventBits(uint32_t) +/// When an event gets set the Broadcaster object will notify the +/// Listener object that is listening for the event (if there is one). +/// +/// Subclasses should provide broadcast bit definitions for any events +/// they vend, typically using an enumeration: +/// \code +/// class Foo : public Broadcaster +/// { +/// public: +/// //---------------------------------------------------------- +/// // Broadcaster event bits definitions. +/// //---------------------------------------------------------- +/// enum +/// { +/// eBroadcastBitOne = (1 << 0), +/// eBroadcastBitTwo = (1 << 1), +/// eBroadcastBitThree = (1 << 2), +/// ... +/// }; +/// \endcode +//---------------------------------------------------------------------- +class Broadcaster { + friend class Listener; + friend class Event; + +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(lldb::BroadcasterManagerSP manager_sp, const char *name); + + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual since this class gets subclassed. + //------------------------------------------------------------------ + virtual ~Broadcaster(); + + void CheckInWithManager(); + + //------------------------------------------------------------------ + /// Broadcast an event which has no associated data. + /// + /// @param[in] event_type + /// The element from the enum defining this broadcaster's events + /// that is being broadcast. + /// + /// @param[in] event_data + /// User event data that will be owned by the lldb::Event that + /// is created internally. + /// + /// @param[in] unique + /// If true, then only add an event of this type if there isn't + /// one already in the queue. + /// + //------------------------------------------------------------------ + void BroadcastEvent(lldb::EventSP &event_sp) { + m_broadcaster_sp->BroadcastEvent(event_sp); + } + + void BroadcastEventIfUnique(lldb::EventSP &event_sp) { + m_broadcaster_sp->BroadcastEventIfUnique(event_sp); + } + + void BroadcastEvent(uint32_t event_type, + const lldb::EventDataSP &event_data_sp) { + m_broadcaster_sp->BroadcastEvent(event_type, event_data_sp); + } + + void BroadcastEvent(uint32_t event_type, EventData *event_data = nullptr) { + m_broadcaster_sp->BroadcastEvent(event_type, event_data); + } + + void BroadcastEventIfUnique(uint32_t event_type, + EventData *event_data = nullptr) { + m_broadcaster_sp->BroadcastEventIfUnique(event_type, event_data); + } + + void Clear() { m_broadcaster_sp->Clear(); } + + virtual void AddInitialEventsToListener(const lldb::ListenerSP &listener_sp, + 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(const lldb::ListenerSP &listener_sp, + uint32_t event_mask) { + return m_broadcaster_sp->AddListener(listener_sp, 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() { return m_broadcaster_name; } + + //------------------------------------------------------------------ + /// Get the event name(s) for one or more event bits. + /// + /// @param[in] event_mask + /// A bit mask that indicates which events to get names for. + /// + /// @return + /// The NULL terminated C string name of this Broadcaster. + //------------------------------------------------------------------ + bool GetEventNames(Stream &s, const uint32_t event_mask, + bool prefix_with_broadcaster_name) const { + return m_broadcaster_sp->GetEventNames(s, event_mask, + prefix_with_broadcaster_name); + } + + //------------------------------------------------------------------ + /// Set the name for an event bit. + /// + /// @param[in] event_mask + /// A bit mask that indicates which events the listener is + /// asking to monitor. + /// + /// @return + /// The NULL terminated C string name of this Broadcaster. + //------------------------------------------------------------------ + void SetEventName(uint32_t event_mask, const char *name) { + m_broadcaster_sp->SetEventName(event_mask, name); + } + + const char *GetEventName(uint32_t event_mask) const { + return m_broadcaster_sp->GetEventName(event_mask); + } + + bool EventTypeHasListeners(uint32_t event_type) { + return m_broadcaster_sp->EventTypeHasListeners(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(const lldb::ListenerSP &listener_sp, + uint32_t event_mask = UINT32_MAX) { + return m_broadcaster_sp->RemoveListener(listener_sp, event_mask); + } + + //------------------------------------------------------------------ + /// Provides a simple mechanism to temporarily redirect events from + /// broadcaster. When you call this function passing in a listener and + /// event type mask, all events from the broadcaster matching the mask + /// will now go to the hijacking listener. + /// Only one hijack can occur at a time. If we need more than this we + /// will have to implement a Listener stack. + /// + /// @param[in] listener + /// A Listener object. You do not need to call StartListeningForEvents + /// for this broadcaster (that would fail anyway since the event bits + /// would most likely be taken by the listener(s) you are usurping. + /// + /// @param[in] event_mask + /// The event bits \a listener wishes to hijack. + /// + /// @return + /// \b True if the event mask could be hijacked, \b false otherwise. + /// + /// @see uint32_t Broadcaster::AddListener (Listener*, uint32_t) + //------------------------------------------------------------------ + bool HijackBroadcaster(const lldb::ListenerSP &listener_sp, + uint32_t event_mask = UINT32_MAX) { + return m_broadcaster_sp->HijackBroadcaster(listener_sp, event_mask); + } + + bool IsHijackedForEvent(uint32_t event_mask) { + return m_broadcaster_sp->IsHijackedForEvent(event_mask); + } + + //------------------------------------------------------------------ + /// Restore the state of the Broadcaster from a previous hijack attempt. + /// + //------------------------------------------------------------------ + void RestoreBroadcaster() { m_broadcaster_sp->RestoreBroadcaster(); } + + // This needs to be filled in if you are going to register the broadcaster + // with the broadcaster + // manager and do broadcaster class matching. + // FIXME: Probably should make a ManagedBroadcaster subclass with all the bits + // needed to work + // with the BroadcasterManager, so that it is clearer how to add one. + virtual ConstString &GetBroadcasterClass() const; + + lldb::BroadcasterManagerSP GetManager(); + +protected: + // BroadcasterImpl contains the actual Broadcaster implementation. The + // Broadcaster makes a BroadcasterImpl + // which lives as long as it does. The Listeners & the Events hold a weak + // pointer to the BroadcasterImpl, + // so that they can survive if a Broadcaster they were listening to is + // destroyed w/o their being able to + // unregister from it (which can happen if the Broadcasters & Listeners are + // being destroyed on separate threads + // simultaneously. + // The Broadcaster itself can't be shared out as a weak pointer, because some + // things that are broadcasters + // (e.g. the Target and the Process) are shared in their own right. + // + // For the most part, the Broadcaster functions dispatch to the + // BroadcasterImpl, and are documented in the + // public Broadcaster API above. + + class BroadcasterImpl { + friend class Listener; + friend class Broadcaster; + + public: + BroadcasterImpl(Broadcaster &broadcaster); + + ~BroadcasterImpl() = default; + + void BroadcastEvent(lldb::EventSP &event_sp); + + void BroadcastEventIfUnique(lldb::EventSP &event_sp); + + void BroadcastEvent(uint32_t event_type, EventData *event_data = nullptr); + + void BroadcastEvent(uint32_t event_type, + const lldb::EventDataSP &event_data_sp); + + void BroadcastEventIfUnique(uint32_t event_type, + EventData *event_data = nullptr); + + void Clear(); + + uint32_t AddListener(const lldb::ListenerSP &listener_sp, + uint32_t event_mask); + + const char *GetBroadcasterName() const { + return m_broadcaster.GetBroadcasterName().AsCString(); + } + + Broadcaster *GetBroadcaster(); + + bool GetEventNames(Stream &s, const uint32_t event_mask, + bool prefix_with_broadcaster_name) const; + + void SetEventName(uint32_t event_mask, const char *name) { + m_event_names[event_mask] = name; + } + + const char *GetEventName(uint32_t event_mask) const { + const auto pos = m_event_names.find(event_mask); + if (pos != m_event_names.end()) + return pos->second.c_str(); + return nullptr; + } + + bool EventTypeHasListeners(uint32_t event_type); + + bool RemoveListener(lldb_private::Listener *listener, + uint32_t event_mask = UINT32_MAX); + + bool RemoveListener(const lldb::ListenerSP &listener_sp, + uint32_t event_mask = UINT32_MAX); + + bool HijackBroadcaster(const lldb::ListenerSP &listener_sp, + uint32_t event_mask = UINT32_MAX); + + bool IsHijackedForEvent(uint32_t event_mask); + + void RestoreBroadcaster(); + + protected: + void PrivateBroadcastEvent(lldb::EventSP &event_sp, bool unique); + + const char *GetHijackingListenerName(); + + //------------------------------------------------------------------ + // + //------------------------------------------------------------------ + typedef llvm::SmallVector, 4> + collection; + typedef std::map event_names_map; + + llvm::SmallVector, 4> + GetListeners(); + + Broadcaster &m_broadcaster; ///< The broadcsater that this implements + event_names_map m_event_names; ///< Optionally define event names for + ///readability and logging for each event bit + collection m_listeners; ///< A list of Listener / event_mask pairs that are + ///listening to this broadcaster. + std::recursive_mutex + m_listeners_mutex; ///< A mutex that protects \a m_listeners. + std::vector m_hijacking_listeners; // A simple mechanism + // to intercept events + // from a broadcaster + std::vector m_hijacking_masks; // At some point we may want to + // have a stack or Listener + // collections, but for now this is just for private hijacking. + + private: + //------------------------------------------------------------------ + // For Broadcaster only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(BroadcasterImpl); + }; + + typedef std::shared_ptr BroadcasterImplSP; + typedef std::weak_ptr BroadcasterImplWP; + + BroadcasterImplSP GetBroadcasterImpl() { return m_broadcaster_sp; } + + const char *GetHijackingListenerName() { + return m_broadcaster_sp->GetHijackingListenerName(); + } + //------------------------------------------------------------------ + // Classes that inherit from Broadcaster can see and modify these + //------------------------------------------------------------------ + +private: + //------------------------------------------------------------------ + // For Broadcaster only + //------------------------------------------------------------------ + BroadcasterImplSP m_broadcaster_sp; + lldb::BroadcasterManagerSP m_manager_sp; + const ConstString + m_broadcaster_name; ///< The name of this broadcaster object. + + DISALLOW_COPY_AND_ASSIGN(Broadcaster); +}; + +} // namespace lldb_private + +#endif // liblldb_Broadcaster_h_ diff --git a/include/lldb/Core/ClangForward.h b/include/lldb/Core/ClangForward.h new file mode 100644 index 000000000..b3cab8a22 --- /dev/null +++ b/include/lldb/Core/ClangForward.h @@ -0,0 +1,139 @@ +//===-- ClangForward.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ClangForward_h_ +#define liblldb_ClangForward_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +#if defined(__cplusplus) + +namespace clang { +namespace Builtin { +class Context; +} + +class Action; +class ASTConsumer; +class ASTContext; +class ASTRecordLayout; +class AddrLabelExpr; +class AnalyzerOptions; +class BinaryOperator; +class ClassTemplateDecl; +class ClassTemplateSpecializationDecl; +class CodeGenOptions; +class CodeGenerator; +class CompilerInstance; +class CompoundStmt; +class CXXBaseSpecifier; +class CXXBoolLiteralExpr; +class CXXFunctionalCastExpr; +class CXXMethodDecl; +class CXXNamedCastExpr; +class CXXRecordDecl; +class CXXThisExpr; +class CharacterLiteral; +class CompoundAssignOperator; +class Decl; +class DeclarationName; +class DeclaratorDecl; +class DeclContext; +class DeclRefExpr; +class DeclStmt; +class DependencyOutputOptions; +class Diagnostic; +class DiagnosticConsumer; +class DiagnosticsEngine; +class DiagnosticOptions; +class EnumDecl; +class EnumConstantDecl; +class Expr; +class ExternalASTSource; +class ExtVectorElementExpr; +class FieldDecl; +class FileManager; +class FileSystemOptions; +class FloatingLiteral; +class FrontendOptions; +class FunctionDecl; +class FunctionTemplateDecl; +class FunctionTemplateSpecializationInfo; +class GotoStmt; +class HeaderSearchOptions; +class IdentifierInfo; +class IdentifierTable; +class IntegerLiteral; +class LabelStmt; +class LangOptions; +class MacroDirective; +class MemberExpr; +class Module; +class NamedDecl; +class NamespaceDecl; +class NonTypeTemplateParmDecl; +class ObjCEncodeExpr; +class ObjCImplicitSetterGetterRefExpr; +class ObjCInterfaceDecl; +class ObjCIvarDecl; +class ObjCIvarRefExpr; +class ObjCMessageExpr; +class ObjCMethodDecl; +class ObjCPropertyRefExpr; +class ObjCProtocolDecl; +class ObjCProtocolExpr; +class ObjCSelectorExpr; +class ObjCSuperExpr; +class ParenExpr; +class ParmVarDecl; +class PredefinedExpr; +class PreprocessorOptions; +class PreprocessorOutputOptions; +class QualType; +class QualifiedNameType; +class RecordDecl; +class SelectorTable; +class SizeOfAlignOfExpr; +class SourceLocation; +class SourceManager; +class Stmt; +class StmtIteratorBase; +class StringLiteral; +class TagDecl; +class TargetInfo; +class TargetOptions; +class TemplateArgument; +class TemplateDecl; +class TemplateParameterList; +class TemplateTemplateParmDecl; +class TemplateTypeParmDecl; +class TextDiagnosticBuffer; +class TranslationUnitDecl; +class Type; +class TypeDecl; +class TypedefDecl; +class TypesCompatibleExpr; +class UnaryOperator; +class ValueDecl; +class VarDecl; +struct PrintingPolicy; +} + +namespace llvm { +class APInt; +class APSInt; +class LLVMContext; +class ExecutionEngine; +} + +#endif // #if defined(__cplusplus) +#endif // liblldb_ClangForward_h_ diff --git a/include/lldb/Core/Communication.h b/include/lldb/Core/Communication.h new file mode 100644 index 000000000..57fa483bd --- /dev/null +++ b/include/lldb/Core/Communication.h @@ -0,0 +1,416 @@ +//===-- 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_ + +#include "lldb/Core/Broadcaster.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Utility/Timeout.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ConnectionStatus, FLAGS_ANONYMOU... +#include "lldb/lldb-forward.h" // for ConnectionSP +#include "lldb/lldb-types.h" // for thread_arg_t, thread_result_t + +#include +#include +#include // for micro +#include + +#include // for size_t +#include // for uint8_t + +namespace lldb_private { +class Connection; +} +namespace lldb_private { +class ConstString; +} +namespace lldb_private { +class Status; +} + +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 (Status *); +/// +/// If true is returned a read thread 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: + FLAGS_ANONYMOUS_ENUM(){ + eBroadcastBitDisconnected = + (1u << 0), ///< Sent when the communications connection is lost. + eBroadcastBitReadThreadGotBytes = + (1u << 1), ///< Sent by the read thread when bytes become available. + eBroadcastBitReadThreadDidExit = + (1u + << 2), ///< Sent by the read thread when it exits to inform clients. + eBroadcastBitReadThreadShouldExit = + (1u << 3), ///< Sent by clients that need to cancel the read thread. + eBroadcastBitPacketAvailable = + (1u << 4), ///< Sent when data received makes a complete packet. + eBroadcastBitNoMorePendingInput = (1u << 5), ///< Sent by the read thread + ///to indicate all pending + ///input has been processed. + kLoUserBroadcastBit = + (1u << 16), ///< Subclasses can used bits 31:16 for any needed events. + kHiUserBroadcastBit = (1u << 31), + eAllEventBits = 0xffffffff}; + + 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. + //------------------------------------------------------------------ + ~Communication() override; + + void Clear(); + + //------------------------------------------------------------------ + /// Connect using the current connection by passing \a url to its + /// connect function. + /// string. + /// + /// @param[in] url + /// A string that contains all information needed by the + /// subclass to connect to another client. + /// + /// @return + /// \b True if the connect succeeded, \b false otherwise. The + /// internal error object should be filled in with an + /// appropriate value based on the result of this function. + /// + /// @see Status& Communication::GetError (); + /// @see bool Connection::Connect (const char *url); + //------------------------------------------------------------------ + lldb::ConnectionStatus Connect(const char *url, Status *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 Status& Communication::GetError (); + /// @see bool Connection::Disconnect (); + //------------------------------------------------------------------ + lldb::ConnectionStatus Disconnect(Status *error_ptr = nullptr); + + //------------------------------------------------------------------ + /// Check if the connection is valid. + /// + /// @return + /// \b True if this object is currently connected, \b false + /// otherwise. + //------------------------------------------------------------------ + bool IsConnected() const; + + bool HasConnection() const; + + lldb_private::Connection *GetConnection() { return m_connection_sp.get(); } + + //------------------------------------------------------------------ + /// Read bytes from the current connection. + /// + /// If no read thread is running, this function call the + /// connection's Connection::Read(...) function to get any available. + /// + /// If a read thread has been started, this function will check for + /// any cached bytes that have already been read and return any + /// currently available bytes. If no bytes are cached, it will wait + /// for the bytes to become available by listening for the \a + /// eBroadcastBitReadThreadGotBytes event. If this function consumes + /// all of the bytes in the cache, it will reset the + /// \a eBroadcastBitReadThreadGotBytes event bit. + /// + /// @param[in] dst + /// A destination buffer that must be at least \a dst_len bytes + /// long. + /// + /// @param[in] dst_len + /// The number of bytes to attempt to read, and also the max + /// number of bytes that can be placed into \a dst. + /// + /// @param[in] timeout + /// A timeout value or llvm::None for no timeout. + /// + /// @return + /// The number of bytes actually read. + /// + /// @see size_t Connection::Read (void *, size_t); + //------------------------------------------------------------------ + size_t Read(void *dst, size_t dst_len, const Timeout &timeout, + lldb::ConnectionStatus &status, Status *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, + Status *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(Status *error_ptr = nullptr); + + //------------------------------------------------------------------ + /// Stops the read thread by cancelling it. + /// + /// @return + /// \b True if the read thread was successfully canceled, \b + /// false otherwise. + //------------------------------------------------------------------ + virtual bool StopReadThread(Status *error_ptr = nullptr); + + virtual bool JoinReadThread(Status *error_ptr = nullptr); + //------------------------------------------------------------------ + /// 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 + /// available. 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); + + //------------------------------------------------------------------ + /// Wait for the read thread to process all outstanding data. + /// + /// After this function returns, the read thread has processed all data that + /// has been waiting in the Connection queue. + /// + //------------------------------------------------------------------ + void SynchronizeWithReadThread(); + + static const char *ConnectionStatusAsCString(lldb::ConnectionStatus status); + + bool GetCloseOnEOF() const { return m_close_on_eof; } + + void SetCloseOnEOF(bool b) { m_close_on_eof = b; } + + static ConstString &GetStaticBroadcasterClass(); + + ConstString &GetBroadcasterClass() const override { + return GetStaticBroadcasterClass(); + } + +protected: + lldb::ConnectionSP m_connection_sp; ///< The connection that is current in use + ///by this communications class. + HostThread m_read_thread; ///< The read thread handle in case we need to + ///cancel the thread. + std::atomic m_read_thread_enabled; + std::atomic m_read_thread_did_exit; + std::string + m_bytes; ///< A buffer to cache bytes read in the ReadThread function. + std::recursive_mutex m_bytes_mutex; ///< A mutex to protect multi-threaded + ///access to the cached bytes. + std::mutex + m_write_mutex; ///< Don't let multiple threads write at the same time... + std::mutex m_synchronize_mutex; + ReadThreadBytesReceived m_callback; + void *m_callback_baton; + bool m_close_on_eof; + + size_t ReadFromConnection(void *dst, size_t dst_len, + const Timeout &timeout, + lldb::ConnectionStatus &status, Status *error_ptr); + + //------------------------------------------------------------------ + /// Append new bytes that get read from the read thread into the + /// internal object byte cache. This will cause a \b + /// eBroadcastBitReadThreadGotBytes event to be broadcast if \a + /// broadcast is true. + /// + /// Subclasses can override this function in order to inspect the + /// received data and check if a packet is available. + /// + /// Subclasses can also still call this function from the + /// overridden method to allow the caching to correctly happen and + /// suppress the broadcasting of the \a eBroadcastBitReadThreadGotBytes + /// event by setting \a broadcast to false. + /// + /// @param[in] src + /// A source buffer that must be at least \a src_len bytes + /// long. + /// + /// @param[in] src_len + /// The number of bytes to append to the cache. + //------------------------------------------------------------------ + virtual void AppendBytesToCache(const uint8_t *src, size_t src_len, + bool broadcast, + lldb::ConnectionStatus status); + + //------------------------------------------------------------------ + /// Get any available bytes from our data cache. If this call + /// empties the data cache, the \b eBroadcastBitReadThreadGotBytes event + /// will be reset to signify no more bytes are available. + /// + /// @param[in] dst + /// A destination buffer that must be at least \a dst_len bytes + /// long. + /// + /// @param[in] dst_len + /// The number of bytes to attempt to read from the cache, + /// and also the max number of bytes that can be placed into + /// \a dst. + /// + /// @return + /// The number of bytes extracted from the data cache. + //------------------------------------------------------------------ + size_t GetCachedBytes(void *dst, size_t dst_len); + +private: + DISALLOW_COPY_AND_ASSIGN(Communication); +}; + +} // namespace lldb_private + +#endif // liblldb_Communication_h_ diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h new file mode 100644 index 000000000..34d35ffe7 --- /dev/null +++ b/include/lldb/Core/Debugger.h @@ -0,0 +1,430 @@ +//===-- 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_ + +// C Includes +#include + +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/FormatEntity.h" +#include "lldb/Core/IOHandler.h" +#include "lldb/Core/SourceManager.h" +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Host/Terminal.h" +#include "lldb/Target/ExecutionContext.h" // for ExecutionContext +#include "lldb/Target/Platform.h" +#include "lldb/Target/TargetList.h" +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/FileSpec.h" // for FileSpec +#include "lldb/Utility/Status.h" // for Status +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ScriptLanguage, Langua... +#include "lldb/lldb-forward.h" // for StreamFileSP, DebuggerSP +#include "lldb/lldb-private-enumerations.h" // for VarSetOperationType +#include "lldb/lldb-private-types.h" // for LoadPluginCallbackType +#include "lldb/lldb-types.h" // for LogOutputCallback, thr... + +#include "llvm/ADT/ArrayRef.h" // for ArrayRef +#include "llvm/ADT/StringMap.h" // for StringMap +#include "llvm/ADT/StringRef.h" // for StringRef +#include "llvm/Support/DynamicLibrary.h" // for DynamicLibrary +#include "llvm/Support/Threading.h" + +#include // for assert +#include // for size_t +#include + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class CommandInterpreter; +} +namespace lldb_private { +class Process; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class Target; +} +namespace llvm { +class raw_ostream; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Debugger Debugger.h "lldb/Core/Debugger.h" +/// @brief A class to manage flag bits. +/// +/// Provides a global root objects for the debugger core. +//---------------------------------------------------------------------- + +class Debugger : public std::enable_shared_from_this, + public UserID, + public Properties { + friend class SourceManager; // For GetSourceFileCache. + +public: + ~Debugger() override; + + static lldb::DebuggerSP + CreateInstance(lldb::LogOutputCallback log_callback = nullptr, + void *baton = nullptr); + + static lldb::TargetSP FindTargetWithProcessID(lldb::pid_t pid); + + static lldb::TargetSP FindTargetWithProcess(Process *process); + + static void Initialize(LoadPluginCallbackType load_plugin_callback); + + static void Terminate(); + + static void SettingsInitialize(); + + static void SettingsTerminate(); + + static void Destroy(lldb::DebuggerSP &debugger_sp); + + static lldb::DebuggerSP FindDebuggerWithID(lldb::user_id_t id); + + static lldb::DebuggerSP + FindDebuggerWithInstanceName(const ConstString &instance_name); + + static size_t GetNumDebuggers(); + + static lldb::DebuggerSP GetDebuggerAtIndex(size_t index); + + static bool FormatDisassemblerAddress(const FormatEntity::Entry *format, + const SymbolContext *sc, + const SymbolContext *prev_sc, + const ExecutionContext *exe_ctx, + const Address *addr, Stream &s); + + void Clear(); + + bool GetAsyncExecution(); + + void SetAsyncExecution(bool async); + + lldb::StreamFileSP GetInputFile() { return m_input_file_sp; } + + lldb::StreamFileSP GetOutputFile() { return m_output_file_sp; } + + lldb::StreamFileSP GetErrorFile() { return m_error_file_sp; } + + void SetInputFileHandle(FILE *fh, bool tranfer_ownership); + + void SetOutputFileHandle(FILE *fh, bool tranfer_ownership); + + void SetErrorFileHandle(FILE *fh, bool tranfer_ownership); + + void SaveInputTerminalState(); + + void RestoreInputTerminalState(); + + lldb::StreamSP GetAsyncOutputStream(); + + lldb::StreamSP GetAsyncErrorStream(); + + CommandInterpreter &GetCommandInterpreter() { + assert(m_command_interpreter_ap.get()); + return *m_command_interpreter_ap; + } + + lldb::ListenerSP GetListener() { return m_listener_sp; } + + // This returns the Debugger's scratch source manager. It won't be able to + // look up files in debug + // information, but it can look up files by absolute path and display them to + // you. + // To get the target's source manager, call GetSourceManager on the target + // instead. + SourceManager &GetSourceManager(); + + lldb::TargetSP GetSelectedTarget() { + return m_target_list.GetSelectedTarget(); + } + + ExecutionContext GetSelectedExecutionContext(); + //------------------------------------------------------------------ + /// Get accessor for the target list. + /// + /// The target list is part of the global debugger object. This + /// the single debugger shared instance to control where targets + /// get created and to allow for tracking and searching for targets + /// based on certain criteria. + /// + /// @return + /// A global shared target list. + //------------------------------------------------------------------ + TargetList &GetTargetList() { return m_target_list; } + + PlatformList &GetPlatformList() { return m_platform_list; } + + void DispatchInputInterrupt(); + + void DispatchInputEndOfFile(); + + //------------------------------------------------------------------ + // If any of the streams are not set, set them to the in/out/err + // stream of the top most input reader to ensure they at least have + // something + //------------------------------------------------------------------ + void AdoptTopIOHandlerFilesIfInvalid(lldb::StreamFileSP &in, + lldb::StreamFileSP &out, + lldb::StreamFileSP &err); + + void PushIOHandler(const lldb::IOHandlerSP &reader_sp); + + bool PopIOHandler(const lldb::IOHandlerSP &reader_sp); + + // Synchronously run an input reader until it is done + void RunIOHandler(const lldb::IOHandlerSP &reader_sp); + + bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp); + + bool CheckTopIOHandlerTypes(IOHandler::Type top_type, + IOHandler::Type second_top_type); + + void PrintAsync(const char *s, size_t len, bool is_stdout); + + ConstString GetTopIOHandlerControlSequence(char ch); + + const char *GetIOHandlerCommandPrefix(); + + const char *GetIOHandlerHelpPrologue(); + + void ClearIOHandlers(); + + bool GetCloseInputOnEOF() const; + + void SetCloseInputOnEOF(bool b); + + bool EnableLog(llvm::StringRef channel, + llvm::ArrayRef categories, + llvm::StringRef log_file, uint32_t log_options, + llvm::raw_ostream &error_stream); + + void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton); + + //---------------------------------------------------------------------- + // Properties Functions + //---------------------------------------------------------------------- + enum StopDisassemblyType { + eStopDisassemblyTypeNever = 0, + eStopDisassemblyTypeNoDebugInfo, + eStopDisassemblyTypeNoSource, + eStopDisassemblyTypeAlways + }; + + Status SetPropertyValue(const ExecutionContext *exe_ctx, + VarSetOperationType op, llvm::StringRef property_path, + llvm::StringRef value) override; + + bool GetAutoConfirm() const; + + const FormatEntity::Entry *GetDisassemblyFormat() const; + + const FormatEntity::Entry *GetFrameFormat() const; + + const FormatEntity::Entry *GetFrameFormatUnique() const; + + const FormatEntity::Entry *GetThreadFormat() const; + + const FormatEntity::Entry *GetThreadStopFormat() const; + + lldb::ScriptLanguage GetScriptLanguage() const; + + bool SetScriptLanguage(lldb::ScriptLanguage script_lang); + + uint32_t GetTerminalWidth() const; + + bool SetTerminalWidth(uint32_t term_width); + + llvm::StringRef GetPrompt() const; + + void SetPrompt(llvm::StringRef p); + void SetPrompt(const char *) = delete; + + bool GetUseExternalEditor() const; + + bool SetUseExternalEditor(bool use_external_editor_p); + + bool GetUseColor() const; + + bool SetUseColor(bool use_color); + + lldb::StopShowColumn GetStopShowColumn() const; + + const FormatEntity::Entry *GetStopShowColumnAnsiPrefix() const; + + const FormatEntity::Entry *GetStopShowColumnAnsiSuffix() const; + + uint32_t GetStopSourceLineCount(bool before) const; + + StopDisassemblyType GetStopDisassemblyDisplay() const; + + uint32_t GetDisassemblyLineCount() const; + + bool GetAutoOneLineSummaries() const; + + bool GetAutoIndent() const; + + bool SetAutoIndent(bool b); + + bool GetPrintDecls() const; + + bool SetPrintDecls(bool b); + + uint32_t GetTabSize() const; + + bool SetTabSize(uint32_t tab_size); + + bool GetEscapeNonPrintables() const; + + bool GetNotifyVoid() const; + + const ConstString &GetInstanceName() { return m_instance_name; } + + bool LoadPlugin(const FileSpec &spec, Status &error); + + void ExecuteIOHandlers(); + + bool IsForwardingEvents(); + + void EnableForwardEvents(const lldb::ListenerSP &listener_sp); + + void CancelForwardEvents(const lldb::ListenerSP &listener_sp); + + bool IsHandlingEvents() const { return m_event_handler_thread.IsJoinable(); } + + Status RunREPL(lldb::LanguageType language, const char *repl_options); + + // This is for use in the command interpreter, when you either want the + // selected target, or if no target + // is present you want to prime the dummy target with entities that will be + // copied over to new targets. + Target *GetSelectedOrDummyTarget(bool prefer_dummy = false); + Target *GetDummyTarget(); + + lldb::BroadcasterManagerSP GetBroadcasterManager() { + return m_broadcaster_manager_sp; + } + +protected: + friend class CommandInterpreter; + friend class REPL; + + bool StartEventHandlerThread(); + + void StopEventHandlerThread(); + + static lldb::thread_result_t EventHandlerThread(lldb::thread_arg_t arg); + + bool HasIOHandlerThread(); + + bool StartIOHandlerThread(); + + void StopIOHandlerThread(); + + void JoinIOHandlerThread(); + + static lldb::thread_result_t IOHandlerThread(lldb::thread_arg_t arg); + + void DefaultEventHandler(); + + void HandleBreakpointEvent(const lldb::EventSP &event_sp); + + void HandleProcessEvent(const lldb::EventSP &event_sp); + + void HandleThreadEvent(const lldb::EventSP &event_sp); + + size_t GetProcessSTDOUT(Process *process, Stream *stream); + + size_t GetProcessSTDERR(Process *process, Stream *stream); + + SourceManager::SourceFileCache &GetSourceFileCache() { + return m_source_file_cache; + } + + void InstanceInitialize(); + + lldb::StreamFileSP m_input_file_sp; + lldb::StreamFileSP m_output_file_sp; + lldb::StreamFileSP m_error_file_sp; + + lldb::BroadcasterManagerSP m_broadcaster_manager_sp; // The debugger acts as a + // broadcaster manager of + // last resort. + // It needs to get constructed before the target_list or any other + // member that might want to broadcast through the debugger. + + TerminalState m_terminal_state; + TargetList m_target_list; + + PlatformList m_platform_list; + lldb::ListenerSP m_listener_sp; + std::unique_ptr m_source_manager_ap; // This is a scratch + // source manager that we + // return if we have no + // targets. + SourceManager::SourceFileCache m_source_file_cache; // All the source managers + // for targets created in + // this debugger used this + // shared + // source file cache. + std::unique_ptr m_command_interpreter_ap; + + IOHandlerStack m_input_reader_stack; + llvm::StringMap> m_log_streams; + std::shared_ptr m_log_callback_stream_sp; + ConstString m_instance_name; + static LoadPluginCallbackType g_load_plugin_callback; + typedef std::vector LoadedPluginsList; + LoadedPluginsList m_loaded_plugins; + HostThread m_event_handler_thread; + HostThread m_io_handler_thread; + Broadcaster m_sync_broadcaster; + lldb::ListenerSP m_forward_listener_sp; + llvm::once_flag m_clear_once; + + //---------------------------------------------------------------------- + // Events for m_sync_broadcaster + //---------------------------------------------------------------------- + enum { + eBroadcastBitEventThreadIsListening = (1 << 0), + }; + +private: + // Use Debugger::CreateInstance() to get a shared pointer to a new + // debugger object + Debugger(lldb::LogOutputCallback m_log_callback, void *baton); + + DISALLOW_COPY_AND_ASSIGN(Debugger); +}; + +} // namespace lldb_private + +#endif // liblldb_Debugger_h_ diff --git a/include/lldb/Core/Disassembler.h b/include/lldb/Core/Disassembler.h new file mode 100644 index 000000000..addc83ad5 --- /dev/null +++ b/include/lldb/Core/Disassembler.h @@ -0,0 +1,559 @@ +//===-- 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_ + +#include "lldb/Core/Address.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/EmulateInstruction.h" +#include "lldb/Core/FormatEntity.h" // for FormatEntity +#include "lldb/Core/Opcode.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Symbol/LineEntry.h" +#include "lldb/Target/ExecutionContext.h" // for ExecutionContext +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for AddressClass, AddressClass... +#include "lldb/lldb-forward.h" // for InstructionSP, DisassemblerSP +#include "lldb/lldb-types.h" // for addr_t, offset_t + +#include "llvm/ADT/StringRef.h" // for StringRef + +#include // for function +#include +#include // for enable_shared_from_this +#include +#include +#include + +#include // for size_t +#include // for uint32_t, int64_t +#include // for FILE + +namespace lldb_private { +class AddressRange; +} +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Debugger; +} +namespace lldb_private { +class Disassembler; +} +namespace lldb_private { +class Module; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class SymbolContextList; +} +namespace lldb_private { +class Target; +} +namespace lldb_private { +struct RegisterInfo; +} +namespace llvm { +template class SmallVectorImpl; +} + +namespace lldb_private { + +class Instruction { +public: + Instruction(const Address &address, + lldb::AddressClass addr_class = lldb::eAddressClassInvalid); + + virtual ~Instruction(); + + const Address &GetAddress() const { return m_address; } + + const char *GetMnemonic(const ExecutionContext *exe_ctx) { + CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx); + return m_opcode_name.c_str(); + } + + const char *GetOperands(const ExecutionContext *exe_ctx) { + CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx); + return m_mnemonics.c_str(); + } + + const char *GetComment(const ExecutionContext *exe_ctx) { + CalculateMnemonicOperandsAndCommentIfNeeded(exe_ctx); + return m_comment.c_str(); + } + + virtual void + CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0; + + lldb::AddressClass GetAddressClass(); + + void SetAddress(const Address &addr) { + // Invalidate the address class to lazily discover + // it if we need to. + m_address_class = lldb::eAddressClassInvalid; + m_address = addr; + } + + //------------------------------------------------------------------ + /// Dump the text representation of this Instruction to a Stream + /// + /// Print the (optional) address, (optional) bytes, opcode, + /// operands, and instruction comments to a stream. + /// + /// @param[in] s + /// The Stream to add the text to. + /// + /// @param[in] show_address + /// Whether the address (using disassembly_addr_format_spec formatting) + /// should be printed. + /// + /// @param[in] show_bytes + /// Whether the bytes of the assembly instruction should be printed. + /// + /// @param[in] max_opcode_byte_size + /// The size (in bytes) of the largest instruction in the list that + /// we are printing (for text justification/alignment purposes) + /// Only needed if show_bytes is true. + /// + /// @param[in] exe_ctx + /// The current execution context, if available. May be used in + /// the assembling of the operands+comments for this instruction. + /// Pass NULL if not applicable. + /// + /// @param[in] sym_ctx + /// The SymbolContext for this instruction. + /// Pass NULL if not available/computed. + /// Only needed if show_address is true. + /// + /// @param[in] prev_sym_ctx + /// The SymbolContext for the previous instruction. Depending on + /// the disassembly address format specification, a change in + /// Symbol / Function may mean that a line is printed with the new + /// symbol/function name. + /// Pass NULL if unavailable, or if this is the first instruction of + /// the InstructionList. + /// Only needed if show_address is true. + /// + /// @param[in] disassembly_addr_format + /// The format specification for how addresses are printed. + /// Only needed if show_address is true. + /// + /// @param[in] max_address_text_size + /// The length of the longest address string at the start of the + /// disassembly line that will be printed (the + /// Debugger::FormatDisassemblerAddress() string) + /// so this method can properly align the instruction opcodes. + /// May be 0 to indicate no indentation/alignment of the opcodes. + //------------------------------------------------------------------ + virtual void Dump(Stream *s, uint32_t max_opcode_byte_size, bool show_address, + bool show_bytes, const ExecutionContext *exe_ctx, + const SymbolContext *sym_ctx, + const SymbolContext *prev_sym_ctx, + const FormatEntity::Entry *disassembly_addr_format, + size_t max_address_text_size); + + virtual bool DoesBranch() = 0; + + virtual bool HasDelaySlot(); + + bool CanSetBreakpoint (); + + virtual size_t Decode(const Disassembler &disassembler, + const DataExtractor &data, + lldb::offset_t data_offset) = 0; + + virtual void SetDescription(llvm::StringRef) { + } // May be overridden in sub-classes that have descriptions. + + lldb::OptionValueSP ReadArray(FILE *in_file, Stream *out_stream, + OptionValue::Type data_type); + + lldb::OptionValueSP ReadDictionary(FILE *in_file, Stream *out_stream); + + bool DumpEmulation(const ArchSpec &arch); + + virtual bool TestEmulation(Stream *stream, const char *test_file_name); + + bool Emulate(const ArchSpec &arch, uint32_t evaluate_options, void *baton, + EmulateInstruction::ReadMemoryCallback read_mem_callback, + EmulateInstruction::WriteMemoryCallback write_mem_calback, + EmulateInstruction::ReadRegisterCallback read_reg_callback, + EmulateInstruction::WriteRegisterCallback write_reg_callback); + + const Opcode &GetOpcode() const { return m_opcode; } + + uint32_t GetData(DataExtractor &data); + + struct Operand { + enum class Type { + Invalid = 0, + Register, + Immediate, + Dereference, + Sum, + Product + } m_type = Type::Invalid; + std::vector m_children; + lldb::addr_t m_immediate = 0; + ConstString m_register; + bool m_negative = false; + bool m_clobbered = false; + + bool IsValid() { return m_type != Type::Invalid; } + + static Operand BuildRegister(ConstString &r); + static Operand BuildImmediate(lldb::addr_t imm, bool neg); + static Operand BuildImmediate(int64_t imm); + static Operand BuildDereference(const Operand &ref); + static Operand BuildSum(const Operand &lhs, const Operand &rhs); + static Operand BuildProduct(const Operand &lhs, const Operand &rhs); + }; + + virtual bool ParseOperands(llvm::SmallVectorImpl &operands) { + return false; + } + + virtual bool IsCall() { return false; } + +protected: + Address m_address; // The section offset address of this instruction + // We include an address class in the Instruction class to + // allow the instruction specify the eAddressClassCodeAlternateISA + // (currently used for thumb), and also to specify data (eAddressClassData). + // The usual value will be eAddressClassCode, but often when + // disassembling memory, you might run into data. This can + // help us to disassemble appropriately. +private: + lldb::AddressClass + m_address_class; // Use GetAddressClass () accessor function! +protected: + Opcode m_opcode; // The opcode for this instruction + std::string m_opcode_name; + std::string m_mnemonics; + std::string m_comment; + bool m_calculated_strings; + + void + CalculateMnemonicOperandsAndCommentIfNeeded(const ExecutionContext *exe_ctx) { + if (!m_calculated_strings) { + m_calculated_strings = true; + CalculateMnemonicOperandsAndComment(exe_ctx); + } + } +}; + +namespace OperandMatchers { +std::function +MatchBinaryOp(std::function base, + std::function left, + std::function right); + +std::function +MatchUnaryOp(std::function base, + std::function child); + +std::function +MatchRegOp(const RegisterInfo &info); + +std::function FetchRegOp(ConstString ®); + +std::function MatchImmOp(int64_t imm); + +std::function FetchImmOp(int64_t &imm); + +std::function +MatchOpType(Instruction::Operand::Type type); +} + +class InstructionList { +public: + InstructionList(); + ~InstructionList(); + + size_t GetSize() const; + + uint32_t GetMaxOpcocdeByteSize() const; + + lldb::InstructionSP GetInstructionAtIndex(size_t idx) const; + + uint32_t GetIndexOfNextBranchInstruction(uint32_t start, + Target &target) const; + + uint32_t GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr, + Target &target); + + uint32_t GetIndexOfInstructionAtAddress(const Address &addr); + + void Clear(); + + void Append(lldb::InstructionSP &inst_sp); + + void Dump(Stream *s, bool show_address, bool show_bytes, + const ExecutionContext *exe_ctx); + +private: + typedef std::vector collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + collection m_instructions; +}; + +class PseudoInstruction : public Instruction { +public: + PseudoInstruction(); + + ~PseudoInstruction() override; + + bool DoesBranch() override; + + bool HasDelaySlot() override; + + void CalculateMnemonicOperandsAndComment( + const ExecutionContext *exe_ctx) override { + // TODO: fill this in and put opcode name into Instruction::m_opcode_name, + // mnemonic into Instruction::m_mnemonics, and any comment into + // Instruction::m_comment + } + + size_t Decode(const Disassembler &disassembler, const DataExtractor &data, + lldb::offset_t data_offset) override; + + void SetOpcode(size_t opcode_size, void *opcode_data); + + void SetDescription(llvm::StringRef description) override; + +protected: + std::string m_description; + + DISALLOW_COPY_AND_ASSIGN(PseudoInstruction); +}; + +class Disassembler : public std::enable_shared_from_this, + public PluginInterface { +public: + enum { + eOptionNone = 0u, + eOptionShowBytes = (1u << 0), + eOptionRawOuput = (1u << 1), + eOptionMarkPCSourceLine = (1u << 2), // Mark the source line that contains + // the current PC (mixed mode only) + eOptionMarkPCAddress = + (1u << 3) // Mark the disassembly line the contains the PC + }; + + enum HexImmediateStyle { + eHexStyleC, + eHexStyleAsm, + }; + + // FindPlugin should be lax about the flavor string (it is too annoying to + // have various internal uses of the + // disassembler fail because the global flavor string gets set wrong. + // Instead, if you get a flavor string you + // don't understand, use the default. Folks who care to check can use the + // FlavorValidForArchSpec method on the + // disassembler they got back. + static lldb::DisassemblerSP + FindPlugin(const ArchSpec &arch, const char *flavor, const char *plugin_name); + + // This version will use the value in the Target settings if flavor is NULL; + static lldb::DisassemblerSP + FindPluginForTarget(const lldb::TargetSP target_sp, const ArchSpec &arch, + const char *flavor, const char *plugin_name); + + static lldb::DisassemblerSP + DisassembleRange(const ArchSpec &arch, const char *plugin_name, + const char *flavor, const ExecutionContext &exe_ctx, + const AddressRange &disasm_range, bool prefer_file_cache); + + static lldb::DisassemblerSP + DisassembleBytes(const ArchSpec &arch, const char *plugin_name, + const char *flavor, const Address &start, const void *bytes, + size_t length, uint32_t max_num_instructions, + bool data_from_file); + + static bool Disassemble(Debugger &debugger, const ArchSpec &arch, + const char *plugin_name, const char *flavor, + const ExecutionContext &exe_ctx, + const AddressRange &range, uint32_t num_instructions, + bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, uint32_t options, + Stream &strm); + + static bool Disassemble(Debugger &debugger, const ArchSpec &arch, + const char *plugin_name, const char *flavor, + const ExecutionContext &exe_ctx, const Address &start, + uint32_t num_instructions, + bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, uint32_t options, + Stream &strm); + + static size_t + Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, + const char *flavor, const ExecutionContext &exe_ctx, + SymbolContextList &sc_list, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, + uint32_t options, Stream &strm); + + static bool + Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, + const char *flavor, const ExecutionContext &exe_ctx, + const ConstString &name, Module *module, + uint32_t num_instructions, bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); + + static bool + Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, + const char *flavor, const ExecutionContext &exe_ctx, + uint32_t num_instructions, bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + Disassembler(const ArchSpec &arch, const char *flavor); + ~Disassembler() override; + + typedef const char *(*SummaryCallback)(const Instruction &inst, + ExecutionContext *exe_context, + void *user_data); + + static bool PrintInstructions(Disassembler *disasm_ptr, Debugger &debugger, + const ArchSpec &arch, + const ExecutionContext &exe_ctx, + uint32_t num_instructions, + bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, + uint32_t options, Stream &strm); + + size_t ParseInstructions(const ExecutionContext *exe_ctx, + const AddressRange &range, Stream *error_strm_ptr, + bool prefer_file_cache); + + size_t ParseInstructions(const ExecutionContext *exe_ctx, + const Address &range, uint32_t num_instructions, + bool prefer_file_cache); + + virtual size_t DecodeInstructions(const Address &base_addr, + const DataExtractor &data, + lldb::offset_t data_offset, + size_t num_instructions, bool append, + bool data_from_file) = 0; + + InstructionList &GetInstructionList(); + + const InstructionList &GetInstructionList() const; + + const ArchSpec &GetArchitecture() const { return m_arch; } + + const char *GetFlavor() const { return m_flavor.c_str(); } + + virtual bool FlavorValidForArchSpec(const lldb_private::ArchSpec &arch, + const char *flavor) = 0; + +protected: + // SourceLine and SourceLinesToDisplay structures are only used in + // the mixed source and assembly display methods internal to this class. + + struct SourceLine { + FileSpec file; + uint32_t line; + uint32_t column; + + SourceLine() : file(), line(LLDB_INVALID_LINE_NUMBER), column(0) {} + + bool operator==(const SourceLine &rhs) const { + return file == rhs.file && line == rhs.line && rhs.column == column; + } + + bool operator!=(const SourceLine &rhs) const { + return file != rhs.file || line != rhs.line || column != rhs.column; + } + + bool IsValid() const { return line != LLDB_INVALID_LINE_NUMBER; } + }; + + struct SourceLinesToDisplay { + std::vector lines; + + // index of the "current" source line, if we want to highlight that + // when displaying the source lines. (as opposed to the surrounding + // source lines provided to give context) + size_t current_source_line; + + // Whether to print a blank line at the end of the source lines. + bool print_source_context_end_eol; + + SourceLinesToDisplay() + : lines(), current_source_line(-1), print_source_context_end_eol(true) { + } + }; + + // Get the function's declaration line number, hopefully a line number earlier + // than the opening curly brace at the start of the function body. + static SourceLine GetFunctionDeclLineEntry(const SymbolContext &sc); + + // Add the provided SourceLine to the map of filenames-to-source-lines-seen. + static void AddLineToSourceLineTables( + SourceLine &line, + std::map> &source_lines_seen); + + // Given a source line, determine if we should print it when we're doing + // mixed source & assembly output. + // We're currently using the target.process.thread.step-avoid-regexp setting + // (which is used for stepping over inlined STL functions by default) to + // determine what source lines to avoid showing. + // + // Returns true if this source line should be elided (if the source line + // should + // not be displayed). + static bool + ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx, + const SymbolContext &sc, SourceLine &line); + + static bool + ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx, + const SymbolContext &sc, LineEntry &line) { + SourceLine sl; + sl.file = line.file; + sl.line = line.line; + sl.column = line.column; + return ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, sl); + }; + + //------------------------------------------------------------------ + // Classes that inherit from Disassembler can see and modify these + //------------------------------------------------------------------ + ArchSpec m_arch; + InstructionList m_instruction_list; + lldb::addr_t m_base_addr; + std::string m_flavor; + +private: + //------------------------------------------------------------------ + // For Disassembler only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(Disassembler); +}; + +} // namespace lldb_private + +#endif // liblldb_Disassembler_h_ diff --git a/include/lldb/Core/DumpDataExtractor.h b/include/lldb/Core/DumpDataExtractor.h new file mode 100644 index 000000000..46e676c23 --- /dev/null +++ b/include/lldb/Core/DumpDataExtractor.h @@ -0,0 +1,95 @@ +//===-- DumpDataExtractor.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_CORE_DUMPDATAEXTRACTOR_H +#define LLDB_CORE_DUMPDATAEXTRACTOR_H + +#include "lldb/lldb-enumerations.h" // for Format +#include "lldb/lldb-types.h" + +#include // for size_t +#include // for uint32_t, uint64_t + +namespace lldb_private { +class DataExtractor; +class ExecutionContextScope; +class Stream; + +//------------------------------------------------------------------ +/// 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 preceded by the address value +/// plus appropriate offset, and a colon and space. Bitfield values +/// can be dumped by calling this function multiple times with the +/// same start offset, format and size, yet differing \a +/// item_bit_size and \a item_bit_offset values. +/// +/// @param[in] s +/// The stream to dump the output to. This value can not be nullptr. +/// +/// @param[in] offset +/// The offset into the data at which to start dumping. +/// +/// @param[in] item_format +/// The format to use when dumping each item. +/// +/// @param[in] item_byte_size +/// The byte size of each item. +/// +/// @param[in] item_count +/// The number of items to dump. +/// +/// @param[in] num_per_line +/// The number of items to display on each line. +/// +/// @param[in] base_addr +/// The base address that gets added to the offset displayed on +/// each line if the value is valid. Is \a base_addr is +/// LLDB_INVALID_ADDRESS then no address values will be prepended +/// to any lines. +/// +/// @param[in] item_bit_size +/// If the value to display is a bitfield, this value should +/// be the number of bits that the bitfield item has within the +/// item's byte size value. This function will need to be called +/// multiple times with identical \a offset and \a item_byte_size +/// values in order to display multiple bitfield values that +/// exist within the same integer value. If the items being +/// displayed are not bitfields, this value should be zero. +/// +/// @param[in] item_bit_offset +/// If the value to display is a bitfield, this value should +/// be the offset in bits, or shift right amount, that the +/// bitfield item occupies within the item's byte size value. +/// This function will need to be called multiple times with +/// identical \a offset and \a item_byte_size values in order +/// to display multiple bitfield values that exist within the +/// same integer value. If the items being displayed are not +/// bitfields, this value should be zero. +/// +/// @return +/// The offset at which dumping ended. +//------------------------------------------------------------------ +lldb::offset_t +DumpDataExtractor(const DataExtractor &DE, Stream *s, lldb::offset_t offset, + lldb::Format item_format, size_t item_byte_size, + size_t item_count, size_t num_per_line, uint64_t base_addr, + uint32_t item_bit_size, uint32_t item_bit_offset, + ExecutionContextScope *exe_scope = nullptr); + +void DumpHexBytes(Stream *s, const void *src, size_t src_len, + uint32_t bytes_per_line, lldb::addr_t base_addr); +} + +#endif diff --git a/include/lldb/Core/EmulateInstruction.h b/include/lldb/Core/EmulateInstruction.h new file mode 100644 index 000000000..bfc9ef054 --- /dev/null +++ b/include/lldb/Core/EmulateInstruction.h @@ -0,0 +1,535 @@ +//===-- EmulateInstruction.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_EmulateInstruction_h_ +#define lldb_EmulateInstruction_h_ + +#include + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Opcode.h" +#include "lldb/Core/PluginInterface.h" + +#include "lldb/Core/Address.h" // for Address +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for RegisterKind, ByteOrder +#include "lldb/lldb-private-enumerations.h" // for InstructionType +#include "lldb/lldb-private-types.h" // for RegisterInfo +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t +#include // for uint32_t, uint64_t, int64_t +namespace lldb_private { +class OptionValueDictionary; +} +namespace lldb_private { +class RegisterContext; +} +namespace lldb_private { +class RegisterValue; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class Target; +} +namespace lldb_private { +class UnwindPlan; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class EmulateInstruction EmulateInstruction.h +/// "lldb/Core/EmulateInstruction.h" +/// @brief A class that allows emulation of CPU opcodes. +/// +/// This class is a plug-in interface that is accessed through the +/// standard static FindPlugin function call in the EmulateInstruction +/// class. The FindPlugin takes a target triple and returns a new object +/// if there is a plug-in that supports the architecture and OS. Four +/// callbacks and a baton are provided. The four callbacks are read +/// register, write register, read memory and write memory. +/// +/// This class is currently designed for these main use cases: +/// - Auto generation of Call Frame Information (CFI) from assembly code +/// - Predicting single step breakpoint locations +/// - Emulating instructions for breakpoint traps +/// +/// Objects can be asked to read an instruction which will cause a call +/// to the read register callback to get the PC, followed by a read +/// memory call to read the opcode. If ReadInstruction () returns true, +/// then a call to EmulateInstruction::EvaluateInstruction () can be +/// made. At this point the EmulateInstruction subclass will use all of +/// the callbacks to emulate an instruction. +/// +/// Clients that provide the callbacks can either do the read/write +/// registers/memory to actually emulate the instruction on a real or +/// virtual CPU, or watch for the EmulateInstruction::Context which +/// is context for the read/write register/memory which explains why +/// the callback is being called. Examples of a context are: +/// "pushing register 3 onto the stack at offset -12", or "adjusting +/// stack pointer by -16". This extra context allows the generation of +/// CFI information from assembly code without having to actually do +/// the read/write register/memory. +/// +/// Clients must be prepared that not all instructions for an +/// Instruction Set Architecture (ISA) will be emulated. +/// +/// Subclasses at the very least should implement the instructions that +/// save and restore registers onto the stack and adjustment to the stack +/// pointer. By just implementing a few instructions for an ISA that are +/// the typical prologue opcodes, you can then generate CFI using a +/// class that will soon be available. +/// +/// Implementing all of the instructions that affect the PC can then +/// allow single step prediction support. +/// +/// Implementing all of the instructions allows for emulation of opcodes +/// for breakpoint traps and will pave the way for "thread centric" +/// debugging. The current debugging model is "process centric" where +/// all threads must be stopped when any thread is stopped; when +/// hitting software breakpoints we must disable the breakpoint by +/// restoring the original breakpoint opcode, single stepping and +/// restoring the breakpoint trap. If all threads were allowed to run +/// then other threads could miss the breakpoint. +/// +/// This class centralizes the code that usually is done in separate +/// code paths in a debugger (single step prediction, finding save +/// restore locations of registers for unwinding stack frame variables) +/// and emulating the instruction is just a bonus. +//---------------------------------------------------------------------- + +class EmulateInstruction : public PluginInterface { +public: + static EmulateInstruction *FindPlugin(const ArchSpec &arch, + InstructionType supported_inst_type, + const char *plugin_name); + + enum ContextType { + eContextInvalid = 0, + // Read an instruction opcode from memory + eContextReadOpcode, + + // Usually used for writing a register value whose source value is an + // immediate + eContextImmediate, + + // Exclusively used when saving a register to the stack as part of the + // prologue + eContextPushRegisterOnStack, + + // Exclusively used when restoring a register off the stack as part of + // the epilogue + eContextPopRegisterOffStack, + + // Add or subtract a value from the stack + eContextAdjustStackPointer, + + // Adjust the frame pointer for the current frame + eContextSetFramePointer, + + // Typically in an epilogue sequence. Copy the frame pointer back + // into the stack pointer, use SP for CFA calculations again. + eContextRestoreStackPointer, + + // Add or subtract a value from a base address register (other than SP) + eContextAdjustBaseRegister, + + // Add or subtract a value from the PC or store a value to the PC. + eContextAdjustPC, + + // Used in WriteRegister callbacks to indicate where the + eContextRegisterPlusOffset, + + // Used in WriteMemory callback to indicate where the data came from + eContextRegisterStore, + + eContextRegisterLoad, + + // Used when performing a PC-relative branch where the + eContextRelativeBranchImmediate, + + // Used when performing an absolute branch where the + eContextAbsoluteBranchRegister, + + // Used when performing a supervisor call to an operating system to + // provide a service: + eContextSupervisorCall, + + // Used when performing a MemU operation to read the PC-relative offset + // from an address. + eContextTableBranchReadMemory, + + // Used when random bits are written into a register + eContextWriteRegisterRandomBits, + + // Used when random bits are written to memory + eContextWriteMemoryRandomBits, + + eContextArithmetic, + + eContextAdvancePC, + + eContextReturnFromException + }; + + enum InfoType { + eInfoTypeRegisterPlusOffset, + eInfoTypeRegisterPlusIndirectOffset, + eInfoTypeRegisterToRegisterPlusOffset, + eInfoTypeRegisterToRegisterPlusIndirectOffset, + eInfoTypeRegisterRegisterOperands, + eInfoTypeOffset, + eInfoTypeRegister, + eInfoTypeImmediate, + eInfoTypeImmediateSigned, + eInfoTypeAddress, + eInfoTypeISAAndImmediate, + eInfoTypeISAAndImmediateSigned, + eInfoTypeISA, + eInfoTypeNoArgs + } InfoType; + + struct Context { + ContextType type; + enum InfoType info_type; + union { + struct RegisterPlusOffset { + RegisterInfo reg; // base register + int64_t signed_offset; // signed offset added to base register + } RegisterPlusOffset; + + struct RegisterPlusIndirectOffset { + RegisterInfo base_reg; // base register number + RegisterInfo offset_reg; // offset register kind + } RegisterPlusIndirectOffset; + + struct RegisterToRegisterPlusOffset { + RegisterInfo data_reg; // source/target register for data + RegisterInfo base_reg; // base register for address calculation + int64_t offset; // offset for address calculation + } RegisterToRegisterPlusOffset; + + struct RegisterToRegisterPlusIndirectOffset { + RegisterInfo base_reg; // base register for address calculation + RegisterInfo offset_reg; // offset register for address calculation + RegisterInfo data_reg; // source/target register for data + } RegisterToRegisterPlusIndirectOffset; + + struct RegisterRegisterOperands { + RegisterInfo + operand1; // register containing first operand for binary op + RegisterInfo + operand2; // register containing second operand for binary op + } RegisterRegisterOperands; + + int64_t signed_offset; // signed offset by which to adjust self (for + // registers only) + + RegisterInfo reg; // plain register + + uint64_t unsigned_immediate; // unsigned immediate value + int64_t signed_immediate; // signed immediate value + + lldb::addr_t address; // direct address + + struct ISAAndImmediate { + uint32_t isa; + uint32_t unsigned_data32; // immediate data + } ISAAndImmediate; + + struct ISAAndImmediateSigned { + uint32_t isa; + int32_t signed_data32; // signed immediate data + } ISAAndImmediateSigned; + + uint32_t isa; + } info; + + Context() : type(eContextInvalid), info_type(eInfoTypeNoArgs) {} + + void SetRegisterPlusOffset(RegisterInfo base_reg, int64_t signed_offset) { + info_type = eInfoTypeRegisterPlusOffset; + info.RegisterPlusOffset.reg = base_reg; + info.RegisterPlusOffset.signed_offset = signed_offset; + } + + void SetRegisterPlusIndirectOffset(RegisterInfo base_reg, + RegisterInfo offset_reg) { + info_type = eInfoTypeRegisterPlusIndirectOffset; + info.RegisterPlusIndirectOffset.base_reg = base_reg; + info.RegisterPlusIndirectOffset.offset_reg = offset_reg; + } + + void SetRegisterToRegisterPlusOffset(RegisterInfo data_reg, + RegisterInfo base_reg, + int64_t offset) { + info_type = eInfoTypeRegisterToRegisterPlusOffset; + info.RegisterToRegisterPlusOffset.data_reg = data_reg; + info.RegisterToRegisterPlusOffset.base_reg = base_reg; + info.RegisterToRegisterPlusOffset.offset = offset; + } + + void SetRegisterToRegisterPlusIndirectOffset(RegisterInfo base_reg, + RegisterInfo offset_reg, + RegisterInfo data_reg) { + info_type = eInfoTypeRegisterToRegisterPlusIndirectOffset; + info.RegisterToRegisterPlusIndirectOffset.base_reg = base_reg; + info.RegisterToRegisterPlusIndirectOffset.offset_reg = offset_reg; + info.RegisterToRegisterPlusIndirectOffset.data_reg = data_reg; + } + + void SetRegisterRegisterOperands(RegisterInfo op1_reg, + RegisterInfo op2_reg) { + info_type = eInfoTypeRegisterRegisterOperands; + info.RegisterRegisterOperands.operand1 = op1_reg; + info.RegisterRegisterOperands.operand2 = op2_reg; + } + + void SetOffset(int64_t signed_offset) { + info_type = eInfoTypeOffset; + info.signed_offset = signed_offset; + } + + void SetRegister(RegisterInfo reg) { + info_type = eInfoTypeRegister; + info.reg = reg; + } + + void SetImmediate(uint64_t immediate) { + info_type = eInfoTypeImmediate; + info.unsigned_immediate = immediate; + } + + void SetImmediateSigned(int64_t signed_immediate) { + info_type = eInfoTypeImmediateSigned; + info.signed_immediate = signed_immediate; + } + + void SetAddress(lldb::addr_t address) { + info_type = eInfoTypeAddress; + info.address = address; + } + void SetISAAndImmediate(uint32_t isa, uint32_t data) { + info_type = eInfoTypeISAAndImmediate; + info.ISAAndImmediate.isa = isa; + info.ISAAndImmediate.unsigned_data32 = data; + } + + void SetISAAndImmediateSigned(uint32_t isa, int32_t data) { + info_type = eInfoTypeISAAndImmediateSigned; + info.ISAAndImmediateSigned.isa = isa; + info.ISAAndImmediateSigned.signed_data32 = data; + } + + void SetISA(uint32_t isa) { + info_type = eInfoTypeISA; + info.isa = isa; + } + + void SetNoArgs() { info_type = eInfoTypeNoArgs; } + + void Dump(Stream &s, EmulateInstruction *instruction) const; + }; + + typedef size_t (*ReadMemoryCallback)(EmulateInstruction *instruction, + void *baton, const Context &context, + lldb::addr_t addr, void *dst, + size_t length); + + typedef size_t (*WriteMemoryCallback)(EmulateInstruction *instruction, + void *baton, const Context &context, + lldb::addr_t addr, const void *dst, + size_t length); + + typedef bool (*ReadRegisterCallback)(EmulateInstruction *instruction, + void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value); + + typedef bool (*WriteRegisterCallback)(EmulateInstruction *instruction, + void *baton, const Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value); + + // Type to represent the condition of an instruction. The UINT32 value is + // reserved for the + // unconditional case and all other value can be used in an architecture + // dependent way. + typedef uint32_t InstructionCondition; + static const InstructionCondition UnconditionalCondition = UINT32_MAX; + + EmulateInstruction(const ArchSpec &arch); + + ~EmulateInstruction() override = default; + + //---------------------------------------------------------------------- + // Mandatory overrides + //---------------------------------------------------------------------- + virtual bool + SupportsEmulatingInstructionsOfType(InstructionType inst_type) = 0; + + virtual bool SetTargetTriple(const ArchSpec &arch) = 0; + + virtual bool ReadInstruction() = 0; + + virtual bool EvaluateInstruction(uint32_t evaluate_options) = 0; + + virtual InstructionCondition GetInstructionCondition() { + return UnconditionalCondition; + } + + virtual bool TestEmulation(Stream *out_stream, ArchSpec &arch, + OptionValueDictionary *test_data) = 0; + + virtual bool GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num, + RegisterInfo ®_info) = 0; + + //---------------------------------------------------------------------- + // Optional overrides + //---------------------------------------------------------------------- + virtual bool SetInstruction(const Opcode &insn_opcode, + const Address &inst_addr, Target *target); + + virtual bool CreateFunctionEntryUnwind(UnwindPlan &unwind_plan); + + static const char *TranslateRegister(lldb::RegisterKind reg_kind, + uint32_t reg_num, std::string ®_name); + + //---------------------------------------------------------------------- + // RegisterInfo variants + //---------------------------------------------------------------------- + bool ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value); + + uint64_t ReadRegisterUnsigned(const RegisterInfo *reg_info, + uint64_t fail_value, bool *success_ptr); + + bool WriteRegister(const Context &context, const RegisterInfo *ref_info, + const RegisterValue ®_value); + + bool WriteRegisterUnsigned(const Context &context, + const RegisterInfo *reg_info, uint64_t reg_value); + + //---------------------------------------------------------------------- + // Register kind and number variants + //---------------------------------------------------------------------- + bool ReadRegister(lldb::RegisterKind reg_kind, uint32_t reg_num, + RegisterValue ®_value); + + bool WriteRegister(const Context &context, lldb::RegisterKind reg_kind, + uint32_t reg_num, const RegisterValue ®_value); + + uint64_t ReadRegisterUnsigned(lldb::RegisterKind reg_kind, uint32_t reg_num, + uint64_t fail_value, bool *success_ptr); + + bool WriteRegisterUnsigned(const Context &context, + lldb::RegisterKind reg_kind, uint32_t reg_num, + uint64_t reg_value); + + size_t ReadMemory(const Context &context, lldb::addr_t addr, void *dst, + size_t dst_len); + + uint64_t ReadMemoryUnsigned(const Context &context, lldb::addr_t addr, + size_t byte_size, uint64_t fail_value, + bool *success_ptr); + + bool WriteMemory(const Context &context, lldb::addr_t addr, const void *src, + size_t src_len); + + bool WriteMemoryUnsigned(const Context &context, lldb::addr_t addr, + uint64_t uval, size_t uval_byte_size); + + uint32_t GetAddressByteSize() const { return m_arch.GetAddressByteSize(); } + + lldb::ByteOrder GetByteOrder() const { return m_arch.GetByteOrder(); } + + const Opcode &GetOpcode() const { return m_opcode; } + + lldb::addr_t GetAddress() const { return m_addr; } + + const ArchSpec &GetArchitecture() const { return m_arch; } + + static size_t ReadMemoryFrame(EmulateInstruction *instruction, void *baton, + const Context &context, lldb::addr_t addr, + void *dst, size_t length); + + static size_t WriteMemoryFrame(EmulateInstruction *instruction, void *baton, + const Context &context, lldb::addr_t addr, + const void *dst, size_t length); + + static bool ReadRegisterFrame(EmulateInstruction *instruction, void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value); + + static bool WriteRegisterFrame(EmulateInstruction *instruction, void *baton, + const Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value); + + static size_t ReadMemoryDefault(EmulateInstruction *instruction, void *baton, + const Context &context, lldb::addr_t addr, + void *dst, size_t length); + + static size_t WriteMemoryDefault(EmulateInstruction *instruction, void *baton, + const Context &context, lldb::addr_t addr, + const void *dst, size_t length); + + static bool ReadRegisterDefault(EmulateInstruction *instruction, void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value); + + static bool WriteRegisterDefault(EmulateInstruction *instruction, void *baton, + const Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value); + + void SetBaton(void *baton); + + void SetCallbacks(ReadMemoryCallback read_mem_callback, + WriteMemoryCallback write_mem_callback, + ReadRegisterCallback read_reg_callback, + WriteRegisterCallback write_reg_callback); + + void SetReadMemCallback(ReadMemoryCallback read_mem_callback); + + void SetWriteMemCallback(WriteMemoryCallback write_mem_callback); + + void SetReadRegCallback(ReadRegisterCallback read_reg_callback); + + void SetWriteRegCallback(WriteRegisterCallback write_reg_callback); + + static bool GetBestRegisterKindAndNumber(const RegisterInfo *reg_info, + lldb::RegisterKind ®_kind, + uint32_t ®_num); + + static uint32_t GetInternalRegisterNumber(RegisterContext *reg_ctx, + const RegisterInfo ®_info); + +protected: + ArchSpec m_arch; + void *m_baton; + ReadMemoryCallback m_read_mem_callback; + WriteMemoryCallback m_write_mem_callback; + ReadRegisterCallback m_read_reg_callback; + WriteRegisterCallback m_write_reg_callback; + lldb::addr_t m_addr; + Opcode m_opcode; + +private: + //------------------------------------------------------------------ + // For EmulateInstruction only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(EmulateInstruction); +}; + +} // namespace lldb_private + +#endif // lldb_EmulateInstruction_h_ diff --git a/include/lldb/Core/Event.h b/include/lldb/Core/Event.h new file mode 100644 index 000000000..f4c7f4769 --- /dev/null +++ b/include/lldb/Core/Event.h @@ -0,0 +1,276 @@ +//===-- 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_ + +#include "lldb/Core/Broadcaster.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-forward.h" // for EventDataSP, ProcessSP, Struct... + +#include "llvm/ADT/StringRef.h" // for StringRef + +#include +#include +#include + +#include // for size_t +#include // for uint32_t + +namespace lldb_private { +class Event; +} +namespace lldb_private { +class Stream; +} + +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(llvm::StringRef str); + + EventDataBytes(const void *src, size_t src_len); + + ~EventDataBytes() override; + + //------------------------------------------------------------------ + // Member functions + //------------------------------------------------------------------ + const ConstString &GetFlavor() const override; + + void Dump(Stream *s) const override; + + const void *GetBytes() const; + + size_t GetByteSize() const; + + void SetBytes(const void *src, size_t src_len); + + void SwapBytes(std::string &new_bytes); + + void SetBytesFromCString(const char *cstr); + + //------------------------------------------------------------------ + // Static functions + //------------------------------------------------------------------ + static const EventDataBytes *GetEventDataFromEvent(const Event *event_ptr); + + static const void *GetBytesFromEvent(const Event *event_ptr); + + static size_t GetByteSizeFromEvent(const Event *event_ptr); + + static const ConstString &GetFlavorString(); + +private: + std::string m_bytes; + + DISALLOW_COPY_AND_ASSIGN(EventDataBytes); +}; + +class EventDataReceipt : public EventData { +public: + EventDataReceipt() : EventData(), m_predicate(false) {} + + ~EventDataReceipt() override {} + + static const ConstString &GetFlavorString() { + static ConstString g_flavor("Process::ProcessEventData"); + return g_flavor; + } + + const ConstString &GetFlavor() const override { return GetFlavorString(); } + + bool WaitForEventReceived( + const std::chrono::microseconds &abstime = std::chrono::microseconds(0), + bool *timed_out = nullptr) { + return m_predicate.WaitForValueEqualTo(true, abstime, timed_out); + } + +private: + Predicate m_predicate; + + void DoOnRemoval(Event *event_ptr) override { + m_predicate.SetValue(true, eBroadcastAlways); + } +}; + +//---------------------------------------------------------------------- +/// This class handles one or more StructuredData::Dictionary entries +/// that are raised for structured data events. +//---------------------------------------------------------------------- + +class EventDataStructuredData : public EventData { +public: + //------------------------------------------------------------------ + // Constructors + //------------------------------------------------------------------ + EventDataStructuredData(); + + EventDataStructuredData(const lldb::ProcessSP &process_sp, + const StructuredData::ObjectSP &object_sp, + const lldb::StructuredDataPluginSP &plugin_sp); + + ~EventDataStructuredData() override; + + //------------------------------------------------------------------ + // Member functions + //------------------------------------------------------------------ + const ConstString &GetFlavor() const override; + + void Dump(Stream *s) const override; + + const lldb::ProcessSP &GetProcess() const; + + const StructuredData::ObjectSP &GetObject() const; + + const lldb::StructuredDataPluginSP &GetStructuredDataPlugin() const; + + void SetProcess(const lldb::ProcessSP &process_sp); + + void SetObject(const StructuredData::ObjectSP &object_sp); + + void SetStructuredDataPlugin(const lldb::StructuredDataPluginSP &plugin_sp); + + //------------------------------------------------------------------ + // Static functions + //------------------------------------------------------------------ + static const EventDataStructuredData * + GetEventDataFromEvent(const Event *event_ptr); + + static lldb::ProcessSP GetProcessFromEvent(const Event *event_ptr); + + static StructuredData::ObjectSP GetObjectFromEvent(const Event *event_ptr); + + static lldb::StructuredDataPluginSP + GetPluginFromEvent(const Event *event_ptr); + + static const ConstString &GetFlavorString(); + +private: + lldb::ProcessSP m_process_sp; + StructuredData::ObjectSP m_object_sp; + lldb::StructuredDataPluginSP m_plugin_sp; + + DISALLOW_COPY_AND_ASSIGN(EventDataStructuredData); +}; + +//---------------------------------------------------------------------- +// lldb::Event +//---------------------------------------------------------------------- +class Event { + friend class Listener; + friend class EventData; + friend class Broadcaster::BroadcasterImpl; + +public: + Event(Broadcaster *broadcaster, uint32_t event_type, + EventData *data = nullptr); + + Event(Broadcaster *broadcaster, uint32_t event_type, + const lldb::EventDataSP &event_data_sp); + + Event(uint32_t event_type, EventData *data = nullptr); + + Event(uint32_t event_type, const lldb::EventDataSP &event_data_sp); + + ~Event(); + + void Dump(Stream *s) const; + + EventData *GetData() { return m_data_sp.get(); } + + const EventData *GetData() const { return m_data_sp.get(); } + + void SetData(EventData *new_data) { m_data_sp.reset(new_data); } + + uint32_t GetType() const { return m_type; } + + void SetType(uint32_t new_type) { m_type = new_type; } + + Broadcaster *GetBroadcaster() const { + Broadcaster::BroadcasterImplSP broadcaster_impl_sp = + m_broadcaster_wp.lock(); + if (broadcaster_impl_sp) + return broadcaster_impl_sp->GetBroadcaster(); + else + return nullptr; + } + + bool BroadcasterIs(Broadcaster *broadcaster) { + Broadcaster::BroadcasterImplSP broadcaster_impl_sp = + m_broadcaster_wp.lock(); + if (broadcaster_impl_sp) + return broadcaster_impl_sp->GetBroadcaster() == broadcaster; + else + return false; + } + + void Clear() { m_data_sp.reset(); } + +private: + // This is only called by Listener when it pops an event off the queue for + // the listener. It calls the Event Data's DoOnRemoval() method, which is + // virtual and can be overridden by the specific data classes. + + void DoOnRemoval(); + + // Called by Broadcaster::BroadcastEvent prior to letting all the listeners + // know about it update the contained broadcaster so that events can be + // popped off one queue and re-broadcast to others. + void SetBroadcaster(Broadcaster *broadcaster) { + m_broadcaster_wp = broadcaster->GetBroadcasterImpl(); + } + + Broadcaster::BroadcasterImplWP + m_broadcaster_wp; // The broadcaster that sent this event + uint32_t m_type; // The bit describing this event + lldb::EventDataSP m_data_sp; // User specific data for this event + + DISALLOW_COPY_AND_ASSIGN(Event); + Event(); // Disallow default constructor +}; + +} // namespace lldb_private + +#endif // liblldb_Event_h_ diff --git a/include/lldb/Core/FileLineResolver.h b/include/lldb/Core/FileLineResolver.h new file mode 100644 index 000000000..54bce4fd2 --- /dev/null +++ b/include/lldb/Core/FileLineResolver.h @@ -0,0 +1,75 @@ +//===-- FileLineResolver.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_FileLineResolver_h_ +#define liblldb_FileLineResolver_h_ + +#include "lldb/Core/SearchFilter.h" // for Searcher, Searcher::CallbackR... +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Utility/FileSpec.h" // for FileSpec +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN + +#include // for uint32_t, UINT32_MAX + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class Stream; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class FileLineResolver FileLineResolver.h "lldb/Core/FileLineResolver.h" +/// @brief This class finds address for source file and line. Optionally, it +/// will look for inlined +/// instances of the file and line specification. +//---------------------------------------------------------------------- + +class FileLineResolver : public Searcher { +public: + FileLineResolver() + : m_file_spec(), + m_line_number(UINT32_MAX), // Set this to zero for all lines in a file + m_sc_list(), m_inlines(true) {} + + FileLineResolver(const FileSpec &resolver, uint32_t line_no, + bool check_inlines); + + ~FileLineResolver() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override; + + void GetDescription(Stream *s) override; + + const SymbolContextList &GetFileLineMatches() { return m_sc_list; } + + void Clear(); + + void Reset(const FileSpec &file_spec, uint32_t line, bool check_inlines); + +protected: + FileSpec m_file_spec; // This is the file spec we are looking for. + uint32_t m_line_number; // This is the line number that we are looking for. + SymbolContextList m_sc_list; + bool m_inlines; // This determines whether the resolver looks for inlined + // functions or not. + +private: + DISALLOW_COPY_AND_ASSIGN(FileLineResolver); +}; + +} // namespace lldb_private + +#endif // liblldb_FileLineResolver_h_ diff --git a/include/lldb/Core/FileSpecList.h b/include/lldb/Core/FileSpecList.h new file mode 100644 index 000000000..3cbffca44 --- /dev/null +++ b/include/lldb/Core/FileSpecList.h @@ -0,0 +1,229 @@ +//===-- 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/Utility/FileSpec.h" + +#include + +#include // for size_t + +namespace lldb_private { +class Stream; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class FileSpecList FileSpecList.h "lldb/Core/FileSpecList.h" +/// @brief A file collection class. +/// +/// A class that contains a mutable list of FileSpec objects. +//---------------------------------------------------------------------- +class FileSpecList { +public: + //------------------------------------------------------------------ + /// Default constructor. + /// + /// Initialize this object with an empty file list. + //------------------------------------------------------------------ + FileSpecList(); + + //------------------------------------------------------------------ + /// Copy constructor. + /// + /// Initialize this object with a copy of the file list from \a rhs. + /// + /// @param[in] rhs + /// A const reference to another file list object. + //------------------------------------------------------------------ + FileSpecList(const FileSpecList &rhs); + + //------------------------------------------------------------------ + /// Destructor. + //------------------------------------------------------------------ + ~FileSpecList(); + + //------------------------------------------------------------------ + /// Assignment operator. + /// + /// Replace the file list in this object with the file list from + /// \a rhs. + /// + /// @param[in] rhs + /// A file list object to copy. + /// + /// @return + /// A const reference to this object. + //------------------------------------------------------------------ + const FileSpecList &operator=(const FileSpecList &rhs); + + //------------------------------------------------------------------ + /// Append a FileSpec object to the list. + /// + /// Appends \a file to the end of the file list. + /// + /// @param[in] file + /// A new file to append to this file list. + //------------------------------------------------------------------ + void Append(const FileSpec &file); + + //------------------------------------------------------------------ + /// Append a FileSpec object if unique. + /// + /// Appends \a file to the end of the file list if it doesn't + /// already exist in the file list. + /// + /// @param[in] file + /// A new file to append to this file list. + /// + /// @return + /// \b true if the file was appended, \b false otherwise. + //------------------------------------------------------------------ + bool AppendIfUnique(const FileSpec &file); + + //------------------------------------------------------------------ + /// Clears the file list. + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + /// Dumps the file list to the supplied stream pointer "s". + /// + /// @param[in] s + /// The stream that will be used to dump the object description. + //------------------------------------------------------------------ + void Dump(Stream *s, const char *separator_cstr = "\n") const; + + //------------------------------------------------------------------ + /// Find a file index. + /// + /// Find the index of the file in the file spec list that matches + /// \a file starting \a idx entries into the file spec list. + /// + /// @param[in] idx + /// An index into the file list. + /// + /// @param[in] file + /// The file specification to search for. + /// + /// @param[in] full + /// Should FileSpec::Equal be called with "full" true or false. + /// + /// @param[in] remove_backup_dots + /// Should FileSpec::Equal be called with "remove_backup_dots" true or + /// false. + /// + /// @return + /// The index of the file that matches \a file if it is found, + /// else UINT32_MAX is returned. + //------------------------------------------------------------------ + size_t FindFileIndex(size_t idx, const FileSpec &file, bool full, + bool remove_backup_dots = false) const; + + //------------------------------------------------------------------ + /// Get file at index. + /// + /// Gets a file from the file list. If \a idx is not a valid index, + /// an empty FileSpec object will be returned. The file objects + /// that are returned can be tested using + /// FileSpec::operator void*(). + /// + /// @param[in] idx + /// An index into the file list. + /// + /// @return + /// A copy of the FileSpec object at index \a idx. If \a idx + /// is out of range, then an empty FileSpec object will be + /// returned. + //------------------------------------------------------------------ + const FileSpec &GetFileSpecAtIndex(size_t idx) const; + + //------------------------------------------------------------------ + /// Get file specification pointer at index. + /// + /// Gets a file from the file list. The file objects that are + /// returned can be tested using FileSpec::operator void*(). + /// + /// @param[in] idx + /// An index into the file list. + /// + /// @return + /// A pointer to a contained FileSpec object at index \a idx. + /// If \a idx is out of range, then an NULL is returned. + //------------------------------------------------------------------ + const FileSpec *GetFileSpecPointerAtIndex(size_t idx) const; + + //------------------------------------------------------------------ + /// Get the memory cost of this object. + /// + /// Return the size in bytes that this object takes in memory. This + /// returns the size in bytes of this object, not any shared string + /// values it may refer to. + /// + /// @return + /// The number of bytes that this object occupies in memory. + /// + /// @see ConstString::StaticMemorySize () + //------------------------------------------------------------------ + size_t MemorySize() const; + + bool IsEmpty() const { return m_files.empty(); } + + //------------------------------------------------------------------ + /// Get the number of files in the file list. + /// + /// @return + /// The number of files in the file spec list. + //------------------------------------------------------------------ + size_t GetSize() const; + + bool Insert(size_t idx, const FileSpec &file) { + if (idx < m_files.size()) { + m_files.insert(m_files.begin() + idx, file); + return true; + } else if (idx == m_files.size()) { + m_files.push_back(file); + return true; + } + return false; + } + + bool Replace(size_t idx, const FileSpec &file) { + if (idx < m_files.size()) { + m_files[idx] = file; + return true; + } + return false; + } + + bool Remove(size_t idx) { + if (idx < m_files.size()) { + m_files.erase(m_files.begin() + idx); + return true; + } + return false; + } + + static size_t GetFilesMatchingPartialPath(const char *path, bool dir_okay, + FileSpecList &matches); + +protected: + typedef std::vector + collection; ///< The collection type for the file list. + collection m_files; ///< A collection of FileSpec objects. +}; + +} // namespace lldb_private + +#endif // #if defined(__cplusplus) +#endif // liblldb_FileSpecList_h_ diff --git a/include/lldb/Core/FormatEntity.h b/include/lldb/Core/FormatEntity.h new file mode 100644 index 000000000..aa5ccb48e --- /dev/null +++ b/include/lldb/Core/FormatEntity.h @@ -0,0 +1,236 @@ +//===-- FormatEntity.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_FormatEntity_h_ +#define liblldb_FormatEntity_h_ + +#include "lldb/Utility/FileSpec.h" // for FileSpec +#include "lldb/Utility/Status.h" +#include "lldb/lldb-enumerations.h" // for Format::eFormatDefault, Format +#include "lldb/lldb-types.h" // for addr_t +#include // for min +#include // for size_t +#include // for uint32_t, uint64_t + +#include +#include + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class ExecutionContext; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class StringList; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class ValueObject; +} +namespace llvm { +class StringRef; +} + +namespace lldb_private { +class FormatEntity { +public: + struct Entry { + enum class Type { + Invalid, + ParentNumber, + ParentString, + InsertString, + Root, + String, + Scope, + Variable, + VariableSynthetic, + ScriptVariable, + ScriptVariableSynthetic, + AddressLoad, + AddressFile, + AddressLoadOrFile, + ProcessID, + ProcessFile, + ScriptProcess, + ThreadID, + ThreadProtocolID, + ThreadIndexID, + ThreadName, + ThreadQueue, + ThreadStopReason, + ThreadReturnValue, + ThreadCompletedExpression, + ScriptThread, + ThreadInfo, + TargetArch, + ScriptTarget, + ModuleFile, + File, + Lang, + FrameIndex, + FrameNoDebug, + FrameRegisterPC, + FrameRegisterSP, + FrameRegisterFP, + FrameRegisterFlags, + FrameRegisterByName, + ScriptFrame, + FunctionID, + FunctionDidChange, + FunctionInitialFunction, + FunctionName, + FunctionNameWithArgs, + FunctionNameNoArgs, + FunctionAddrOffset, + FunctionAddrOffsetConcrete, + FunctionLineOffset, + FunctionPCOffset, + FunctionInitial, + FunctionChanged, + FunctionIsOptimized, + LineEntryFile, + LineEntryLineNumber, + LineEntryStartAddress, + LineEntryEndAddress, + CurrentPCArrow + }; + + enum FormatType { None, UInt32, UInt64, CString }; + + struct Definition { + const char *name; + const char *string; // Insert this exact string into the output + Entry::Type type; + FormatType format_type; // uint32_t, uint64_t, cstr, or anything that can + // be formatted by printf or lldb::Format + uint64_t data; + uint32_t num_children; + Definition *children; // An array of "num_children" Definition entries, + bool keep_separator; + }; + + Entry(Type t = Type::Invalid, const char *s = nullptr, + const char *f = nullptr) + : string(s ? s : ""), printf_format(f ? f : ""), children(), + definition(nullptr), type(t), fmt(lldb::eFormatDefault), number(0), + deref(false) {} + + Entry(llvm::StringRef s); + Entry(char ch); + + void AppendChar(char ch); + + void AppendText(const llvm::StringRef &s); + + void AppendText(const char *cstr); + + void AppendEntry(const Entry &&entry) { children.push_back(entry); } + + void Clear() { + string.clear(); + printf_format.clear(); + children.clear(); + definition = nullptr; + type = Type::Invalid; + fmt = lldb::eFormatDefault; + number = 0; + deref = false; + } + + static const char *TypeToCString(Type t); + + void Dump(Stream &s, int depth = 0) const; + + bool operator==(const Entry &rhs) const { + if (string != rhs.string) + return false; + if (printf_format != rhs.printf_format) + return false; + const size_t n = children.size(); + const size_t m = rhs.children.size(); + for (size_t i = 0; i < std::min(n, m); ++i) { + if (!(children[i] == rhs.children[i])) + return false; + } + if (children != rhs.children) + return false; + if (definition != rhs.definition) + return false; + if (type != rhs.type) + return false; + if (fmt != rhs.fmt) + return false; + if (deref != rhs.deref) + return false; + return true; + } + + std::string string; + std::string printf_format; + std::vector children; + Definition *definition; + Type type; + lldb::Format fmt; + lldb::addr_t number; + bool deref; + }; + + static bool Format(const Entry &entry, Stream &s, const SymbolContext *sc, + const ExecutionContext *exe_ctx, const Address *addr, + ValueObject *valobj, bool function_changed, + bool initial_function); + + static bool FormatStringRef(const llvm::StringRef &format, Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, ValueObject *valobj, + bool function_changed, bool initial_function); + + static bool FormatCString(const char *format, Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, ValueObject *valobj, + bool function_changed, bool initial_function); + + static Status Parse(const llvm::StringRef &format, Entry &entry); + + static Status ExtractVariableInfo(llvm::StringRef &format_str, + llvm::StringRef &variable_name, + llvm::StringRef &variable_format); + + static size_t AutoComplete(llvm::StringRef s, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches); + + //---------------------------------------------------------------------- + // Format the current elements into the stream \a s. + // + // The root element will be stripped off and the format str passed in + // will be either an empty string (print a description of this object), + // or contain a . separated series like a domain name that identifies + // further sub elements to display. + //---------------------------------------------------------------------- + static bool FormatFileSpec(const FileSpec &file, Stream &s, + llvm::StringRef elements, + llvm::StringRef element_format); + +protected: + static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, + uint32_t depth); +}; +} // namespace lldb_private + +#endif // liblldb_FormatEntity_h_ diff --git a/include/lldb/Core/IOHandler.h b/include/lldb/Core/IOHandler.h new file mode 100644 index 000000000..ebf56d790 --- /dev/null +++ b/include/lldb/Core/IOHandler.h @@ -0,0 +1,608 @@ +//===-- IOHandler.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_IOHandler_h_ +#define liblldb_IOHandler_h_ + +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Flags.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StringList.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-forward.h" // for IOHandlerSP, StreamFileSP +#include "llvm/ADT/StringRef.h" // for StringRef + +#include +#include +#include +#include + +#include // for uint32_t +#include // for FILE + +namespace lldb_private { +class Debugger; +} + +namespace curses { +class Application; +typedef std::unique_ptr ApplicationAP; +} // namespace curses + +namespace lldb_private { + +class IOHandler { +public: + enum class Type { + CommandInterpreter, + CommandList, + Confirm, + Curses, + Expression, + REPL, + ProcessIO, + PythonInterpreter, + PythonCode, + Other + }; + + IOHandler(Debugger &debugger, IOHandler::Type type); + + IOHandler(Debugger &debugger, IOHandler::Type type, + const lldb::StreamFileSP &input_sp, + const lldb::StreamFileSP &output_sp, + const lldb::StreamFileSP &error_sp, uint32_t flags); + + virtual ~IOHandler(); + + // Each IOHandler gets to run until it is done. It should read data + // from the "in" and place output into "out" and "err and return + // when done. + virtual void Run() = 0; + + // Called when an input reader should relinquish its control so another + // can be pushed onto the IO handler stack, or so the current IO + // handler can pop itself off the stack + + virtual void Cancel() = 0; + + // Called when CTRL+C is pressed which usually causes + // Debugger::DispatchInputInterrupt to be called. + + virtual bool Interrupt() = 0; + + virtual void GotEOF() = 0; + + virtual bool IsActive() { return m_active && !m_done; } + + virtual void SetIsDone(bool b) { m_done = b; } + + virtual bool GetIsDone() { return m_done; } + + Type GetType() const { return m_type; } + + virtual void Activate() { m_active = true; } + + virtual void Deactivate() { m_active = false; } + + virtual const char *GetPrompt() { + // Prompt support isn't mandatory + return nullptr; + } + + virtual bool SetPrompt(llvm::StringRef prompt) { + // Prompt support isn't mandatory + return false; + } + bool SetPrompt(const char *) = delete; + + virtual ConstString GetControlSequence(char ch) { return ConstString(); } + + virtual const char *GetCommandPrefix() { return nullptr; } + + virtual const char *GetHelpPrologue() { return nullptr; } + + int GetInputFD(); + + int GetOutputFD(); + + int GetErrorFD(); + + FILE *GetInputFILE(); + + FILE *GetOutputFILE(); + + FILE *GetErrorFILE(); + + lldb::StreamFileSP &GetInputStreamFile(); + + lldb::StreamFileSP &GetOutputStreamFile(); + + lldb::StreamFileSP &GetErrorStreamFile(); + + Debugger &GetDebugger() { return m_debugger; } + + void *GetUserData() { return m_user_data; } + + void SetUserData(void *user_data) { m_user_data = user_data; } + + Flags &GetFlags() { return m_flags; } + + const Flags &GetFlags() const { return m_flags; } + + //------------------------------------------------------------------ + /// Check if the input is being supplied interactively by a user + /// + /// This will return true if the input stream is a terminal (tty or + /// pty) and can cause IO handlers to do different things (like + /// for a confirmation when deleting all breakpoints). + //------------------------------------------------------------------ + bool GetIsInteractive(); + + //------------------------------------------------------------------ + /// Check if the input is coming from a real terminal. + /// + /// A real terminal has a valid size with a certain number of rows + /// and columns. If this function returns true, then terminal escape + /// sequences are expected to work (cursor movement escape sequences, + /// clearing lines, etc). + //------------------------------------------------------------------ + bool GetIsRealTerminal(); + + void SetPopped(bool b); + + void WaitForPop(); + + virtual void PrintAsync(Stream *stream, const char *s, size_t len) { + stream->Write(s, len); + stream->Flush(); + } + +protected: + Debugger &m_debugger; + lldb::StreamFileSP m_input_sp; + lldb::StreamFileSP m_output_sp; + lldb::StreamFileSP m_error_sp; + Predicate m_popped; + Flags m_flags; + Type m_type; + void *m_user_data; + bool m_done; + bool m_active; + +private: + DISALLOW_COPY_AND_ASSIGN(IOHandler); +}; + +//------------------------------------------------------------------ +/// A delegate class for use with IOHandler subclasses. +/// +/// The IOHandler delegate is designed to be mixed into classes so +/// they can use an IOHandler subclass to fetch input and notify the +/// object that inherits from this delegate class when a token is +/// received. +//------------------------------------------------------------------ +class IOHandlerDelegate { +public: + enum class Completion { None, LLDBCommand, Expression }; + + IOHandlerDelegate(Completion completion = Completion::None) + : m_completion(completion), m_io_handler_done(false) {} + + virtual ~IOHandlerDelegate() = default; + + virtual void IOHandlerActivated(IOHandler &io_handler) {} + + virtual void IOHandlerDeactivated(IOHandler &io_handler) {} + + virtual int IOHandlerComplete(IOHandler &io_handler, const char *current_line, + const char *cursor, const char *last_char, + int skip_first_n_matches, int max_matches, + StringList &matches); + + virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; } + + //------------------------------------------------------------------ + /// Called when a new line is created or one of an identified set of + /// indentation characters is typed. + /// + /// This function determines how much indentation should be added + /// or removed to match the recommended amount for the final line. + /// + /// @param[in] io_handler + /// The IOHandler that responsible for input. + /// + /// @param[in] lines + /// The current input up to the line to be corrected. Lines + /// following the line containing the cursor are not included. + /// + /// @param[in] cursor_position + /// The number of characters preceding the cursor on the final + /// line at the time. + /// + /// @return + /// Returns an integer describing the number of spaces needed + /// to correct the indentation level. Positive values indicate + /// that spaces should be added, while negative values represent + /// spaces that should be removed. + //------------------------------------------------------------------ + virtual int IOHandlerFixIndentation(IOHandler &io_handler, + const StringList &lines, + int cursor_position) { + return 0; + } + + //------------------------------------------------------------------ + /// Called when a line or lines have been retrieved. + /// + /// This function can handle the current line and possibly call + /// IOHandler::SetIsDone(true) when the IO handler is done like when + /// "quit" is entered as a command, of when an empty line is + /// received. It is up to the delegate to determine when a line + /// should cause a IOHandler to exit. + //------------------------------------------------------------------ + virtual void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) = 0; + + virtual void IOHandlerInputInterrupted(IOHandler &io_handler, + std::string &data) {} + + //------------------------------------------------------------------ + /// Called to determine whether typing enter after the last line in + /// \a lines should end input. This function will not be called on + /// IOHandler objects that are getting single lines. + /// @param[in] io_handler + /// The IOHandler that responsible for updating the lines. + /// + /// @param[in] lines + /// The current multi-line content. May be altered to provide + /// alternative input when complete. + /// + /// @return + /// Return an boolean to indicate whether input is complete, + /// true indicates that no additional input is necessary, while + /// false indicates that more input is required. + //------------------------------------------------------------------ + virtual bool IOHandlerIsInputComplete(IOHandler &io_handler, + StringList &lines) { + // Impose no requirements for input to be considered + // complete. subclasses should do something more intelligent. + return true; + } + + virtual ConstString IOHandlerGetControlSequence(char ch) { + return ConstString(); + } + + virtual const char *IOHandlerGetCommandPrefix() { return nullptr; } + + virtual const char *IOHandlerGetHelpPrologue() { return nullptr; } + + //------------------------------------------------------------------ + // Intercept the IOHandler::Interrupt() calls and do something. + // + // Return true if the interrupt was handled, false if the IOHandler + // should continue to try handle the interrupt itself. + //------------------------------------------------------------------ + virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; } + +protected: + Completion m_completion; // Support for common builtin completions + bool m_io_handler_done; +}; + +//---------------------------------------------------------------------- +// IOHandlerDelegateMultiline +// +// A IOHandlerDelegate that handles terminating multi-line input when +// the last line is equal to "end_line" which is specified in the +// constructor. +//---------------------------------------------------------------------- +class IOHandlerDelegateMultiline : public IOHandlerDelegate { +public: + IOHandlerDelegateMultiline(const char *end_line, + Completion completion = Completion::None) + : IOHandlerDelegate(completion), + m_end_line((end_line && end_line[0]) ? end_line : "") {} + + ~IOHandlerDelegateMultiline() override = default; + + ConstString IOHandlerGetControlSequence(char ch) override { + if (ch == 'd') + return ConstString(m_end_line + "\n"); + return ConstString(); + } + + bool IOHandlerIsInputComplete(IOHandler &io_handler, + StringList &lines) override { + // Determine whether the end of input signal has been entered + const size_t num_lines = lines.GetSize(); + if (num_lines > 0 && lines[num_lines - 1] == m_end_line) { + // Remove the terminal line from "lines" so it doesn't appear in + // the resulting input and return true to indicate we are done + // getting lines + lines.PopBack(); + return true; + } + return false; + } + +protected: + const std::string m_end_line; +}; + +class IOHandlerEditline : public IOHandler { +public: + IOHandlerEditline(Debugger &debugger, IOHandler::Type type, + const char *editline_name, // Used for saving history files + llvm::StringRef prompt, llvm::StringRef continuation_prompt, + bool multi_line, bool color_prompts, + uint32_t line_number_start, // If non-zero show line numbers + // starting at + // 'line_number_start' + IOHandlerDelegate &delegate); + + IOHandlerEditline(Debugger &debugger, IOHandler::Type type, + const lldb::StreamFileSP &input_sp, + const lldb::StreamFileSP &output_sp, + const lldb::StreamFileSP &error_sp, uint32_t flags, + const char *editline_name, // Used for saving history files + llvm::StringRef prompt, llvm::StringRef continuation_prompt, + bool multi_line, bool color_prompts, + uint32_t line_number_start, // If non-zero show line numbers + // starting at + // 'line_number_start' + IOHandlerDelegate &delegate); + + IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *, + const char *, bool, bool, uint32_t, + IOHandlerDelegate &) = delete; + + IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::StreamFileSP &, + const lldb::StreamFileSP &, const lldb::StreamFileSP &, + uint32_t, const char *, const char *, const char *, bool, + bool, uint32_t, IOHandlerDelegate &) = delete; + + ~IOHandlerEditline() override; + + void Run() override; + + void Cancel() override; + + bool Interrupt() override; + + void GotEOF() override; + + void Activate() override; + + void Deactivate() override; + + ConstString GetControlSequence(char ch) override { + return m_delegate.IOHandlerGetControlSequence(ch); + } + + const char *GetCommandPrefix() override { + return m_delegate.IOHandlerGetCommandPrefix(); + } + + const char *GetHelpPrologue() override { + return m_delegate.IOHandlerGetHelpPrologue(); + } + + const char *GetPrompt() override; + + bool SetPrompt(llvm::StringRef prompt) override; + bool SetPrompt(const char *prompt) = delete; + + const char *GetContinuationPrompt(); + + void SetContinuationPrompt(llvm::StringRef prompt); + void SetContinuationPrompt(const char *) = delete; + + bool GetLine(std::string &line, bool &interrupted); + + bool GetLines(StringList &lines, bool &interrupted); + + void SetBaseLineNumber(uint32_t line); + + bool GetInterruptExits() { return m_interrupt_exits; } + + void SetInterruptExits(bool b) { m_interrupt_exits = b; } + + const StringList *GetCurrentLines() const { return m_current_lines_ptr; } + + uint32_t GetCurrentLineIndex() const; + + void PrintAsync(Stream *stream, const char *s, size_t len) override; + +private: +#ifndef LLDB_DISABLE_LIBEDIT + static bool IsInputCompleteCallback(Editline *editline, StringList &lines, + void *baton); + + static int FixIndentationCallback(Editline *editline, const StringList &lines, + int cursor_position, void *baton); + + static int AutoCompleteCallback(const char *current_line, const char *cursor, + const char *last_char, + int skip_first_n_matches, int max_matches, + StringList &matches, void *baton); +#endif + +protected: +#ifndef LLDB_DISABLE_LIBEDIT + std::unique_ptr m_editline_ap; +#endif + IOHandlerDelegate &m_delegate; + std::string m_prompt; + std::string m_continuation_prompt; + StringList *m_current_lines_ptr; + uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt + uint32_t m_curr_line_idx; + bool m_multi_line; + bool m_color_prompts; + bool m_interrupt_exits; + bool m_editing; // Set to true when fetching a line manually (not using + // libedit) +}; + +// The order of base classes is important. Look at the constructor of +// IOHandlerConfirm +// to see how. +class IOHandlerConfirm : public IOHandlerDelegate, public IOHandlerEditline { +public: + IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt, + bool default_response); + + ~IOHandlerConfirm() override; + + bool GetResponse() const { return m_user_response; } + + int IOHandlerComplete(IOHandler &io_handler, const char *current_line, + const char *cursor, const char *last_char, + int skip_first_n_matches, int max_matches, + StringList &matches) override; + + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) override; + +protected: + const bool m_default_response; + bool m_user_response; +}; + +class IOHandlerCursesGUI : public IOHandler { +public: + IOHandlerCursesGUI(Debugger &debugger); + + ~IOHandlerCursesGUI() override; + + void Run() override; + + void Cancel() override; + + bool Interrupt() override; + + void GotEOF() override; + + void Activate() override; + + void Deactivate() override; + +protected: + curses::ApplicationAP m_app_ap; +}; + +class IOHandlerCursesValueObjectList : public IOHandler { +public: + IOHandlerCursesValueObjectList(Debugger &debugger, + ValueObjectList &valobj_list); + + ~IOHandlerCursesValueObjectList() override; + + void Run() override; + + void GotEOF() override; + +protected: + ValueObjectList m_valobj_list; +}; + +class IOHandlerStack { +public: + IOHandlerStack() : m_stack(), m_mutex(), m_top(nullptr) {} + + ~IOHandlerStack() = default; + + size_t GetSize() const { + std::lock_guard guard(m_mutex); + return m_stack.size(); + } + + void Push(const lldb::IOHandlerSP &sp) { + if (sp) { + std::lock_guard guard(m_mutex); + sp->SetPopped(false); + m_stack.push_back(sp); + // Set m_top the non-locking IsTop() call + m_top = sp.get(); + } + } + + bool IsEmpty() const { + std::lock_guard guard(m_mutex); + return m_stack.empty(); + } + + lldb::IOHandlerSP Top() { + lldb::IOHandlerSP sp; + { + std::lock_guard guard(m_mutex); + if (!m_stack.empty()) + sp = m_stack.back(); + } + return sp; + } + + void Pop() { + std::lock_guard guard(m_mutex); + if (!m_stack.empty()) { + lldb::IOHandlerSP sp(m_stack.back()); + m_stack.pop_back(); + sp->SetPopped(true); + } + // Set m_top the non-locking IsTop() call + + m_top = (m_stack.empty() ? nullptr : m_stack.back().get()); + } + + std::recursive_mutex &GetMutex() { return m_mutex; } + + bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const { + return m_top == io_handler_sp.get(); + } + + bool CheckTopIOHandlerTypes(IOHandler::Type top_type, + IOHandler::Type second_top_type) { + std::lock_guard guard(m_mutex); + const size_t num_io_handlers = m_stack.size(); + return (num_io_handlers >= 2 && + m_stack[num_io_handlers - 1]->GetType() == top_type && + m_stack[num_io_handlers - 2]->GetType() == second_top_type); + } + + ConstString GetTopIOHandlerControlSequence(char ch) { + return ((m_top != nullptr) ? m_top->GetControlSequence(ch) : ConstString()); + } + + const char *GetTopIOHandlerCommandPrefix() { + return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr); + } + + const char *GetTopIOHandlerHelpPrologue() { + return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr); + } + + void PrintAsync(Stream *stream, const char *s, size_t len); + +protected: + typedef std::vector collection; + collection m_stack; + mutable std::recursive_mutex m_mutex; + IOHandler *m_top; + +private: + DISALLOW_COPY_AND_ASSIGN(IOHandlerStack); +}; + +} // namespace lldb_private + +#endif // liblldb_IOHandler_h_ diff --git a/include/lldb/Core/IOStreamMacros.h b/include/lldb/Core/IOStreamMacros.h new file mode 100644 index 000000000..2562f179c --- /dev/null +++ b/include/lldb/Core/IOStreamMacros.h @@ -0,0 +1,42 @@ +//===-- 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 + +#define RAW_HEXBASE std::setfill('0') << std::hex << std::right +#define HEXBASE '0' << 'x' << RAW_HEXBASE +#define RAWHEX8(x) RAW_HEXBASE << std::setw(2) << ((uint32_t)(x)) +#define RAWHEX16 RAW_HEXBASE << std::setw(4) +#define RAWHEX32 RAW_HEXBASE << std::setw(8) +#define RAWHEX64 RAW_HEXBASE << std::setw(16) +#define HEX8(x) HEXBASE << std::setw(2) << ((uint32_t)(x)) +#define HEX16 HEXBASE << std::setw(4) +#define HEX32 HEXBASE << std::setw(8) +#define HEX64 HEXBASE << std::setw(16) +#define RAW_HEX(x) RAW_HEXBASE << std::setw(sizeof(x) * 2) << (x) +#define HEX(x) HEXBASE << std::setw(sizeof(x) * 2) << (x) +#define HEX_SIZE(x, sz) HEXBASE << std::setw((sz)) << (x) +#define STRING_WIDTH(w) std::setfill(' ') << std::setw(w) +#define LEFT_STRING_WIDTH(s, w) \ + std::left << std::setfill(' ') << std::setw(w) << (s) << std::right +#define DECIMAL std::dec << std::setfill(' ') +#define DECIMAL_WIDTH(w) DECIMAL << std::setw(w) +//#define FLOAT(n, d) std::setfill(' ') << std::setw((n)+(d)+1) << +//std::setprecision(d) << std::showpoint << std::fixed +#define INDENT_WITH_SPACES(iword_idx) \ + std::setfill(' ') << std::setw((iword_idx)) << "" +#define INDENT_WITH_TABS(iword_idx) \ + std::setfill('\t') << std::setw((iword_idx)) << "" + +#endif // #if defined(__cplusplus) +#endif // liblldb_IOStreamMacros_h_ diff --git a/include/lldb/Core/Listener.h b/include/lldb/Core/Listener.h new file mode 100644 index 000000000..3d12f8fb3 --- /dev/null +++ b/include/lldb/Core/Listener.h @@ -0,0 +1,161 @@ +//===-- 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_ + +#include "lldb/Core/Broadcaster.h" // for Broadcaster::BroadcasterImplWP +#include "lldb/Utility/Timeout.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-forward.h" // for BroadcasterManagerWP, EventSP + +#include +#include +#include +#include // for owner_less, enable_shared_from_this +#include +#include // for micro +#include +#include + +#include // for size_t +#include // for uint32_t + +namespace lldb_private { +class ConstString; +} +namespace lldb_private { +class Event; +} + +namespace lldb_private { + +class Listener : public std::enable_shared_from_this { +public: + typedef bool (*HandleBroadcastCallback)(lldb::EventSP &event_sp, void *baton); + + friend class Broadcaster; + friend class BroadcasterManager; + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + // + // Listeners have to be constructed into shared pointers - at least if you + // want them to listen to Broadcasters, +protected: + Listener(const char *name); + +public: + static lldb::ListenerSP MakeListener(const char *name); + + ~Listener(); + + void AddEvent(lldb::EventSP &event); + + void Clear(); + + const char *GetName() { return m_name.c_str(); } + + uint32_t StartListeningForEventSpec(lldb::BroadcasterManagerSP manager_sp, + const BroadcastEventSpec &event_spec); + + bool StopListeningForEventSpec(lldb::BroadcasterManagerSP manager_sp, + const BroadcastEventSpec &event_spec); + + uint32_t StartListeningForEvents(Broadcaster *broadcaster, + uint32_t event_mask); + + uint32_t StartListeningForEvents(Broadcaster *broadcaster, + uint32_t event_mask, + HandleBroadcastCallback callback, + void *callback_user_data); + + bool StopListeningForEvents(Broadcaster *broadcaster, uint32_t event_mask); + + Event *PeekAtNextEvent(); + + Event *PeekAtNextEventForBroadcaster(Broadcaster *broadcaster); + + Event *PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster, + uint32_t event_type_mask); + + // Returns true if an event was received, false if we timed out. + bool GetEvent(lldb::EventSP &event_sp, const Timeout &timeout); + + bool GetEventForBroadcaster(Broadcaster *broadcaster, lldb::EventSP &event_sp, + const Timeout &timeout); + + bool GetEventForBroadcasterWithType(Broadcaster *broadcaster, + uint32_t event_type_mask, + lldb::EventSP &event_sp, + const Timeout &timeout); + + size_t HandleBroadcastEvent(lldb::EventSP &event_sp); + +private: + //------------------------------------------------------------------ + // Classes that inherit from Listener can see and modify these + //------------------------------------------------------------------ + struct BroadcasterInfo { + BroadcasterInfo(uint32_t mask, HandleBroadcastCallback cb = nullptr, + void *ud = nullptr) + : event_mask(mask), callback(cb), callback_user_data(ud) {} + + uint32_t event_mask; + HandleBroadcastCallback callback; + void *callback_user_data; + }; + + typedef std::multimap> + broadcaster_collection; + typedef std::list event_collection; + typedef std::vector + broadcaster_manager_collection; + + bool + FindNextEventInternal(std::unique_lock &lock, + Broadcaster *broadcaster, // nullptr for any broadcaster + const ConstString *sources, // nullptr for any event + uint32_t num_sources, uint32_t event_type_mask, + lldb::EventSP &event_sp, bool remove); + + bool GetEventInternal(const Timeout &timeout, + Broadcaster *broadcaster, // nullptr for any broadcaster + const ConstString *sources, // nullptr for any event + uint32_t num_sources, uint32_t event_type_mask, + lldb::EventSP &event_sp); + + std::string m_name; + broadcaster_collection m_broadcasters; + std::recursive_mutex m_broadcasters_mutex; // Protects m_broadcasters + event_collection m_events; + std::mutex m_events_mutex; // Protects m_broadcasters and m_events + std::condition_variable m_events_condition; + broadcaster_manager_collection m_broadcaster_managers; + + void BroadcasterWillDestruct(Broadcaster *); + + void BroadcasterManagerWillDestruct(lldb::BroadcasterManagerSP manager_sp); + + // broadcaster_collection::iterator + // FindBroadcasterWithMask (Broadcaster *broadcaster, + // uint32_t event_mask, + // bool exact); + + //------------------------------------------------------------------ + // For Listener only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(Listener); +}; + +} // namespace lldb_private + +#endif // liblldb_Select_h_ diff --git a/include/lldb/Core/LoadedModuleInfoList.h b/include/lldb/Core/LoadedModuleInfoList.h new file mode 100644 index 000000000..ecbe3548d --- /dev/null +++ b/include/lldb/Core/LoadedModuleInfoList.h @@ -0,0 +1,119 @@ +//===-- LoadedModuleInfoList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LoadedModuleInfoList_h_ +#define liblldb_LoadedModuleInfoList_h_ + +// C Includes + +// C++ Includes +#include + +// Other libraries and framework includes +#include "lldb/lldb-private-forward.h" + +namespace lldb_private { +class LoadedModuleInfoList { +public: + class LoadedModuleInfo { + public: + enum e_data_point { + e_has_name = 0, + e_has_base, + e_has_dynamic, + e_has_link_map, + e_num + }; + + LoadedModuleInfo() { + for (uint32_t i = 0; i < e_num; ++i) + m_has[i] = false; + }; + + void set_name(const std::string &name) { + m_name = name; + m_has[e_has_name] = true; + } + bool get_name(std::string &out) const { + out = m_name; + return m_has[e_has_name]; + } + + void set_base(const lldb::addr_t base) { + m_base = base; + m_has[e_has_base] = true; + } + bool get_base(lldb::addr_t &out) const { + out = m_base; + return m_has[e_has_base]; + } + + void set_base_is_offset(bool is_offset) { m_base_is_offset = is_offset; } + bool get_base_is_offset(bool &out) const { + out = m_base_is_offset; + return m_has[e_has_base]; + } + + void set_link_map(const lldb::addr_t addr) { + m_link_map = addr; + m_has[e_has_link_map] = true; + } + bool get_link_map(lldb::addr_t &out) const { + out = m_link_map; + return m_has[e_has_link_map]; + } + + void set_dynamic(const lldb::addr_t addr) { + m_dynamic = addr; + m_has[e_has_dynamic] = true; + } + bool get_dynamic(lldb::addr_t &out) const { + out = m_dynamic; + return m_has[e_has_dynamic]; + } + + bool has_info(e_data_point datum) const { + assert(datum < e_num); + return m_has[datum]; + } + + bool operator==(LoadedModuleInfo const &rhs) const { + if (e_num != rhs.e_num) + return false; + + for (size_t i = 0; i < e_num; ++i) { + if (m_has[i] != rhs.m_has[i]) + return false; + } + + return (m_base == rhs.m_base) && (m_link_map == rhs.m_link_map) && + (m_dynamic == rhs.m_dynamic) && (m_name == rhs.m_name); + } + + protected: + bool m_has[e_num]; + std::string m_name; + lldb::addr_t m_link_map; + lldb::addr_t m_base; + bool m_base_is_offset; + lldb::addr_t m_dynamic; + }; + + LoadedModuleInfoList() : m_list(), m_link_map(LLDB_INVALID_ADDRESS) {} + + void add(const LoadedModuleInfo &mod) { m_list.push_back(mod); } + + void clear() { m_list.clear(); } + + std::vector m_list; + lldb::addr_t m_link_map; +}; +} // namespace lldb_private + +#endif // liblldb_LoadedModuleInfoList_h_ diff --git a/include/lldb/Core/Mangled.h b/include/lldb/Core/Mangled.h new file mode 100644 index 000000000..22778fabe --- /dev/null +++ b/include/lldb/Core/Mangled.h @@ -0,0 +1,317 @@ +//===-- 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/Utility/ConstString.h" +#include "lldb/lldb-enumerations.h" // for LanguageType +#include "llvm/ADT/StringRef.h" // for StringRef + +#include // for size_t + +namespace lldb_private { +class RegularExpression; +} +namespace lldb_private { +class Stream; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Mangled Mangled.h "lldb/Core/Mangled.h" +/// @brief A class that handles mangled names. +/// +/// Designed to handle mangled names. The demangled version of any names +/// will be computed when the demangled name is accessed through the +/// Demangled() acccessor. This class can also tokenize the demangled +/// version of the name for powerful searches. Functions and symbols +/// could make instances of this class for their mangled names. Uniqued +/// string pools are used for the mangled, demangled, and token string +/// values to allow for faster comparisons and for efficient memory use. +//---------------------------------------------------------------------- +class Mangled { +public: + enum NamePreference { + ePreferMangled, + ePreferDemangled, + ePreferDemangledWithoutArguments + }; + + enum ManglingScheme { + eManglingSchemeNone = 0, + eManglingSchemeMSVC, + eManglingSchemeItanium + }; + + //---------------------------------------------------------------------- + /// Default constructor. + /// + /// Initialize with both mangled and demangled names empty. + //---------------------------------------------------------------------- + Mangled(); + + //---------------------------------------------------------------------- + /// Construct with name. + /// + /// Constructor with an optional string and a boolean indicating if it is + /// the mangled version. + /// + /// @param[in] name + /// The already const name to copy into this object. + /// + /// @param[in] is_mangled + /// If \b true then \a name is a mangled name, if \b false then + /// \a name is demangled. + //---------------------------------------------------------------------- + Mangled(const ConstString &name, bool is_mangled); + Mangled(llvm::StringRef name, bool is_mangled); + + //---------------------------------------------------------------------- + /// Construct with name. + /// + /// Constructor with an optional string and auto-detect if \a name is + /// mangled or not. + /// + /// @param[in] name + /// The already const name to copy into this object. + //---------------------------------------------------------------------- + explicit Mangled(const ConstString &name); + + explicit Mangled(llvm::StringRef name); + + //---------------------------------------------------------------------- + /// Destructor + /// + /// Releases its ref counts on the mangled and demangled strings that + /// live in the global string pool. + //---------------------------------------------------------------------- + ~Mangled(); + + //---------------------------------------------------------------------- + /// Convert to pointer operator. + /// + /// This allows code to check a Mangled object to see if it contains + /// a valid mangled name using code such as: + /// + /// @code + /// Mangled mangled(...); + /// if (mangled) + /// { ... + /// @endcode + /// + /// @return + /// A pointer to this object if either the mangled or unmangled + /// name is set, NULL otherwise. + //---------------------------------------------------------------------- + operator void *() const; + + //---------------------------------------------------------------------- + /// Logical NOT operator. + /// + /// This allows code to check a Mangled object to see if it contains + /// an empty mangled name using code such as: + /// + /// @code + /// Mangled mangled(...); + /// if (!mangled) + /// { ... + /// @endcode + /// + /// @return + /// Returns \b true if the object has an empty mangled and + /// unmangled name, \b false otherwise. + //---------------------------------------------------------------------- + bool operator!() const; + + //---------------------------------------------------------------------- + /// Clear the mangled and demangled values. + //---------------------------------------------------------------------- + void Clear(); + + //---------------------------------------------------------------------- + /// Compare the mangled string values + /// + /// Compares the Mangled::GetName() string in \a lhs and \a rhs. + /// + /// @param[in] lhs + /// A const reference to the Left Hand Side object to compare. + /// + /// @param[in] rhs + /// A const reference to the Right Hand Side object to compare. + /// + /// @return + /// @li -1 if \a lhs is less than \a rhs + /// @li 0 if \a lhs is equal to \a rhs + /// @li 1 if \a lhs is greater than \a rhs + //---------------------------------------------------------------------- + static int Compare(const Mangled &lhs, const Mangled &rhs); + + //---------------------------------------------------------------------- + /// Dump a description of this object to a Stream \a s. + /// + /// Dump a Mangled object to stream \a s. We don't force our + /// demangled name to be computed currently (we don't use the accessor). + /// + /// @param[in] s + /// The stream to which to dump the object description. + //---------------------------------------------------------------------- + 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 description. + //---------------------------------------------------------------------- + void DumpDebug(Stream *s) const; + + //---------------------------------------------------------------------- + /// Demangled name get accessor. + /// + /// @return + /// A const reference to the demangled name string object. + //---------------------------------------------------------------------- + const ConstString &GetDemangledName(lldb::LanguageType language) const; + + //---------------------------------------------------------------------- + /// Display demangled name get accessor. + /// + /// @return + /// A const reference to the display demangled name string object. + //---------------------------------------------------------------------- + ConstString GetDisplayDemangledName(lldb::LanguageType language) const; + + void SetDemangledName(const ConstString &name) { m_demangled = name; } + + void SetMangledName(const ConstString &name) { m_mangled = name; } + + //---------------------------------------------------------------------- + /// Mangled name get accessor. + /// + /// @return + /// A reference to the mangled name string object. + //---------------------------------------------------------------------- + ConstString &GetMangledName() { return m_mangled; } + + //---------------------------------------------------------------------- + /// Mangled name get accessor. + /// + /// @return + /// A const reference to the mangled name string object. + //---------------------------------------------------------------------- + const ConstString &GetMangledName() const { return m_mangled; } + + //---------------------------------------------------------------------- + /// Best name get accessor. + /// + /// @param[in] preference + /// Which name would you prefer to get? + /// + /// @return + /// A const reference to the preferred name string object if this + /// object has a valid name of that kind, else a const reference to the + /// other name is returned. + //---------------------------------------------------------------------- + ConstString GetName(lldb::LanguageType language, + NamePreference preference = ePreferDemangled) const; + + //---------------------------------------------------------------------- + /// Check if "name" matches either the mangled or demangled name. + /// + /// @param[in] name + /// A name to match against both strings. + /// + /// @return + /// \b True if \a name matches either name, \b false otherwise. + //---------------------------------------------------------------------- + bool NameMatches(const ConstString &name, lldb::LanguageType language) const { + if (m_mangled == name) + return true; + return GetDemangledName(language) == name; + } + + bool NameMatches(const RegularExpression ®ex, + lldb::LanguageType language) const; + + //---------------------------------------------------------------------- + /// Get the memory cost of this object. + /// + /// Return the size in bytes that this object takes in memory. This + /// returns the size in bytes of this object, not any shared string + /// values it may refer to. + /// + /// @return + /// The number of bytes that this object occupies in memory. + /// + /// @see ConstString::StaticMemorySize () + //---------------------------------------------------------------------- + size_t MemorySize() const; + + //---------------------------------------------------------------------- + /// Set the string value in this object. + /// + /// If \a is_mangled is \b true, then the mangled named is set to \a + /// name, else the demangled name is set to \a name. + /// + /// @param[in] name + /// The already const version of the name for this object. + /// + /// @param[in] is_mangled + /// If \b true then \a name is a mangled name, if \b false then + /// \a name is demangled. + //---------------------------------------------------------------------- + void SetValue(const ConstString &name, bool is_mangled); + + //---------------------------------------------------------------------- + /// Set the string value in this object. + /// + /// This version auto detects if the string is mangled by inspecting the + /// string value and looking for common mangling prefixes. + /// + /// @param[in] name + /// The already const version of the name for this object. + //---------------------------------------------------------------------- + void SetValue(const ConstString &name); + + //---------------------------------------------------------------------- + /// Try to guess the language from the mangling. + /// + /// For a mangled name to have a language it must have both a mangled + /// and a demangled name and it can be guessed from the mangling what + /// the language is. Note: this will return C++ for any language that + /// uses Itanium ABI mangling. + /// + /// Standard C function names will return eLanguageTypeUnknown because + /// they aren't mangled and it isn't clear what language the name + /// represents (there will be no mangled name). + /// + /// @return + /// The language for the mangled/demangled name, eLanguageTypeUnknown + /// if there is no mangled or demangled counterpart. + //---------------------------------------------------------------------- + lldb::LanguageType GuessLanguage() const; + +private: + //---------------------------------------------------------------------- + /// Mangled member variables. + //---------------------------------------------------------------------- + ConstString m_mangled; ///< The mangled version of the name + mutable ConstString m_demangled; ///< Mutable so we can get it on demand with + ///a const version of this object +}; + +Stream &operator<<(Stream &s, const Mangled &obj); + +} // namespace lldb_private + +#endif // #if defined(__cplusplus) +#endif // liblldb_Mangled_h_ diff --git a/include/lldb/Core/MappedHash.h b/include/lldb/Core/MappedHash.h new file mode 100644 index 000000000..18d383ed5 --- /dev/null +++ b/include/lldb/Core/MappedHash.h @@ -0,0 +1,483 @@ +//===-- MappedHash.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_MappedHash_h_ +#define liblldb_MappedHash_h_ + +// C Includes +#include +#include + +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Stream.h" + +class MappedHash { +public: + enum HashFunctionType { + eHashFunctionDJB = 0u // Daniel J Bernstein hash function that is also used + // by the ELF GNU_HASH sections + }; + + static uint32_t HashStringUsingDJB(const char *s) { + uint32_t h = 5381; + + for (unsigned char c = *s; c; c = *++s) + h = ((h << 5) + h) + c; + + return h; + } + + static uint32_t HashString(uint32_t hash_function, const char *s) { + if (!s) + return 0; + + switch (hash_function) { + case MappedHash::eHashFunctionDJB: + return HashStringUsingDJB(s); + + default: + break; + } + llvm_unreachable("Invalid hash function index"); + } + + static const uint32_t HASH_MAGIC = 0x48415348u; + static const uint32_t HASH_CIGAM = 0x48534148u; + + template struct Header { + typedef T HeaderData; + + uint32_t + magic; // HASH_MAGIC or HASH_CIGAM magic value to allow endian detection + uint16_t version; // Version number + uint16_t hash_function; // The hash function enumeration that was used + uint32_t bucket_count; // The number of buckets in this hash table + uint32_t hashes_count; // The total number of unique hash values and hash + // data offsets in this table + uint32_t header_data_len; // The size in bytes of the "header_data" template + // member below + HeaderData header_data; // + + Header() + : magic(HASH_MAGIC), version(1), hash_function(eHashFunctionDJB), + bucket_count(0), hashes_count(0), header_data_len(sizeof(T)), + header_data() {} + + virtual ~Header() = default; + + size_t GetByteSize() const { + return sizeof(magic) + sizeof(version) + sizeof(hash_function) + + sizeof(bucket_count) + sizeof(hashes_count) + + sizeof(header_data_len) + header_data_len; + } + + virtual size_t GetByteSize(const HeaderData &header_data) = 0; + + void SetHeaderDataByteSize(uint32_t header_data_byte_size) { + header_data_len = header_data_byte_size; + } + + void Dump(lldb_private::Stream &s) { + s.Printf("header.magic = 0x%8.8x\n", magic); + s.Printf("header.version = 0x%4.4x\n", version); + s.Printf("header.hash_function = 0x%4.4x\n", hash_function); + s.Printf("header.bucket_count = 0x%8.8x %u\n", bucket_count, + bucket_count); + s.Printf("header.hashes_count = 0x%8.8x %u\n", hashes_count, + hashes_count); + s.Printf("header.header_data_len = 0x%8.8x %u\n", header_data_len, + header_data_len); + } + + virtual lldb::offset_t Read(lldb_private::DataExtractor &data, + lldb::offset_t offset) { + if (data.ValidOffsetForDataOfSize( + offset, sizeof(magic) + sizeof(version) + sizeof(hash_function) + + sizeof(bucket_count) + sizeof(hashes_count) + + sizeof(header_data_len))) { + magic = data.GetU32(&offset); + if (magic != HASH_MAGIC) { + if (magic == HASH_CIGAM) { + switch (data.GetByteOrder()) { + case lldb::eByteOrderBig: + data.SetByteOrder(lldb::eByteOrderLittle); + break; + case lldb::eByteOrderLittle: + data.SetByteOrder(lldb::eByteOrderBig); + break; + default: + return LLDB_INVALID_OFFSET; + } + } else { + // Magic bytes didn't match + version = 0; + return LLDB_INVALID_OFFSET; + } + } + + version = data.GetU16(&offset); + if (version != 1) { + // Unsupported version + return LLDB_INVALID_OFFSET; + } + hash_function = data.GetU16(&offset); + if (hash_function == 4) + hash_function = 0; // Deal with pre-release version of this table... + bucket_count = data.GetU32(&offset); + hashes_count = data.GetU32(&offset); + header_data_len = data.GetU32(&offset); + return offset; + } + return LLDB_INVALID_OFFSET; + } + // + // // Returns a buffer that contains a serialized version of this + // table + // // that must be freed with free(). + // virtual void * + // Write (int fd); + }; + + template + class ExportTable { + public: + typedef __HeaderDataType HeaderDataType; + typedef Header HeaderType; + typedef __KeyType KeyType; + typedef __ValueType ValueType; + + struct Entry { + uint32_t hash; + KeyType key; + ValueType value; + }; + + typedef std::vector ValueArrayType; + + typedef std::map HashData; + // Map a name hash to one or more name infos + typedef std::map HashToHashData; + + virtual KeyType GetKeyForStringType(const char *cstr) const = 0; + + virtual size_t GetByteSize(const HashData &key_to_key_values) = 0; + + virtual bool WriteHashData(const HashData &hash_data, + lldb_private::Stream &ostrm) = 0; + // + void AddEntry(const char *cstr, const ValueType &value) { + Entry entry; + entry.hash = MappedHash::HashString(eHashFunctionDJB, cstr); + entry.key = GetKeyForStringType(cstr); + entry.value = value; + m_entries.push_back(entry); + } + + void Save(const HeaderDataType &header_data, lldb_private::Stream &ostrm) { + if (m_entries.empty()) + return; + + const uint32_t num_entries = m_entries.size(); + uint32_t i = 0; + + HeaderType header; + + header.magic = HASH_MAGIC; + header.version = 1; + header.hash_function = eHashFunctionDJB; + header.bucket_count = 0; + header.hashes_count = 0; + header.prologue_length = header_data.GetByteSize(); + + // We need to figure out the number of unique hashes first before we can + // calculate the number of buckets we want to use. + typedef std::vector hash_coll; + hash_coll unique_hashes; + unique_hashes.resize(num_entries); + for (i = 0; i < num_entries; ++i) + unique_hashes[i] = m_entries[i].hash; + std::sort(unique_hashes.begin(), unique_hashes.end()); + hash_coll::iterator pos = + std::unique(unique_hashes.begin(), unique_hashes.end()); + const size_t num_unique_hashes = + std::distance(unique_hashes.begin(), pos); + + if (num_unique_hashes > 1024) + header.bucket_count = num_unique_hashes / 4; + else if (num_unique_hashes > 16) + header.bucket_count = num_unique_hashes / 2; + else + header.bucket_count = num_unique_hashes; + if (header.bucket_count == 0) + header.bucket_count = 1; + + std::vector hash_buckets; + std::vector hash_indexes(header.bucket_count, 0); + std::vector hash_values; + std::vector hash_offsets; + hash_buckets.resize(header.bucket_count); + uint32_t bucket_entry_empties = 0; + // StreamString hash_file_data(Stream::eBinary, + // dwarf->GetObjectFile()->GetAddressByteSize(), + // dwarf->GetObjectFile()->GetByteSize()); + + // Push all of the hashes into their buckets and create all bucket + // entries all populated with data. + for (i = 0; i < num_entries; ++i) { + const uint32_t hash = m_entries[i].hash; + const uint32_t bucket_idx = hash % header.bucket_count; + const uint32_t strp_offset = m_entries[i].str_offset; + const uint32_t die_offset = m_entries[i].die_offset; + hash_buckets[bucket_idx][hash][strp_offset].push_back(die_offset); + } + + // Now for each bucket we write the bucket value which is the + // number of hashes and the hash index encoded into a single + // 32 bit unsigned integer. + for (i = 0; i < header.bucket_count; ++i) { + HashToHashData &bucket_entry = hash_buckets[i]; + + if (bucket_entry.empty()) { + // Empty bucket + ++bucket_entry_empties; + hash_indexes[i] = UINT32_MAX; + } else { + const uint32_t hash_value_index = hash_values.size(); + uint32_t hash_count = 0; + typename HashToHashData::const_iterator pos, end = bucket_entry.end(); + for (pos = bucket_entry.begin(); pos != end; ++pos) { + hash_values.push_back(pos->first); + hash_offsets.push_back(GetByteSize(pos->second)); + ++hash_count; + } + + hash_indexes[i] = hash_value_index; + } + } + header.hashes_count = hash_values.size(); + + // Write the header out now that we have the hash_count + header.Write(ostrm); + + // Now for each bucket we write the start index of the hashes + // for the current bucket, or UINT32_MAX if the bucket is empty + for (i = 0; i < header.bucket_count; ++i) { + ostrm.PutHex32(hash_indexes[i]); + } + + // Now we need to write out all of the hash values + for (i = 0; i < header.hashes_count; ++i) { + ostrm.PutHex32(hash_values[i]); + } + + // Now we need to write out all of the hash data offsets, + // there is an offset for each hash in the hashes array + // that was written out above + for (i = 0; i < header.hashes_count; ++i) { + ostrm.PutHex32(hash_offsets[i]); + } + + // Now we write the data for each hash and verify we got the offset + // correct above... + for (i = 0; i < header.bucket_count; ++i) { + HashToHashData &bucket_entry = hash_buckets[i]; + + typename HashToHashData::const_iterator pos, end = bucket_entry.end(); + for (pos = bucket_entry.begin(); pos != end; ++pos) { + if (!bucket_entry.empty()) { + WriteHashData(pos->second); + } + } + } + } + + protected: + typedef std::vector collection; + collection m_entries; + }; + + // A class for reading and using a saved hash table from a block of data + // in memory + template + class MemoryTable { + public: + typedef __HeaderType HeaderType; + typedef __KeyType KeyType; + typedef __HashData HashData; + + enum Result { + eResultKeyMatch = 0u, // The entry was found, key matched and "pair" was + // filled in successfully + eResultKeyMismatch = + 1u, // Bucket hash data collision, but key didn't match + eResultEndOfHashData = 2u, // The chain of items for this hash data in + // this bucket is terminated, search no more + eResultError = 3u // Status parsing the hash data, abort + }; + + struct Pair { + KeyType key; + HashData value; + }; + + MemoryTable(lldb_private::DataExtractor &data) + : m_header(), m_hash_indexes(nullptr), m_hash_values(nullptr), + m_hash_offsets(nullptr) { + lldb::offset_t offset = m_header.Read(data, 0); + if (offset != LLDB_INVALID_OFFSET && IsValid()) { + m_hash_indexes = (const uint32_t *)data.GetData( + &offset, m_header.bucket_count * sizeof(uint32_t)); + m_hash_values = (const uint32_t *)data.GetData( + &offset, m_header.hashes_count * sizeof(uint32_t)); + m_hash_offsets = (const uint32_t *)data.GetData( + &offset, m_header.hashes_count * sizeof(uint32_t)); + } + } + + virtual ~MemoryTable() = default; + + bool IsValid() const { + return m_header.version == 1 && + m_header.hash_function == eHashFunctionDJB && + m_header.bucket_count > 0; + } + + uint32_t GetHashIndex(uint32_t bucket_idx) const { + if (m_hash_indexes && bucket_idx < m_header.bucket_count) + return m_hash_indexes[bucket_idx]; + return UINT32_MAX; + } + + uint32_t GetHashValue(uint32_t hash_idx) const { + if (m_hash_values && hash_idx < m_header.hashes_count) + return m_hash_values[hash_idx]; + return UINT32_MAX; + } + + uint32_t GetHashDataOffset(uint32_t hash_idx) const { + if (m_hash_offsets && hash_idx < m_header.hashes_count) + return m_hash_offsets[hash_idx]; + return UINT32_MAX; + } + + bool Find(const char *name, Pair &pair) const { + if (!name || !name[0]) + return false; + + if (IsValid()) { + const uint32_t bucket_count = m_header.bucket_count; + const uint32_t hash_count = m_header.hashes_count; + const uint32_t hash_value = + MappedHash::HashString(m_header.hash_function, name); + const uint32_t bucket_idx = hash_value % bucket_count; + uint32_t hash_idx = GetHashIndex(bucket_idx); + if (hash_idx < hash_count) { + for (; hash_idx < hash_count; ++hash_idx) { + const uint32_t curr_hash_value = GetHashValue(hash_idx); + if (curr_hash_value == hash_value) { + lldb::offset_t hash_data_offset = GetHashDataOffset(hash_idx); + while (hash_data_offset != UINT32_MAX) { + const lldb::offset_t prev_hash_data_offset = hash_data_offset; + Result hash_result = + GetHashDataForName(name, &hash_data_offset, pair); + // Check the result of getting our hash data + switch (hash_result) { + case eResultKeyMatch: + return true; + + case eResultKeyMismatch: + if (prev_hash_data_offset == hash_data_offset) + return false; + break; + + case eResultEndOfHashData: + // The last HashData for this key has been reached, stop + // searching + return false; + case eResultError: + // Status parsing the hash data, abort + return false; + } + } + } + if ((curr_hash_value % bucket_count) != bucket_idx) + break; + } + } + } + return false; + } + + // This method must be implemented in any subclasses. + // The KeyType is user specified and must somehow result in a string + // value. For example, the KeyType might be a string offset in a string + // table and subclasses can store their string table as a member of the + // subclass and return a valie "const char *" given a "key". The value + // could also be a C string pointer, in which case just returning "key" + // will suffice. + virtual const char *GetStringForKeyType(KeyType key) const = 0; + + virtual bool ReadHashData(uint32_t hash_data_offset, + HashData &hash_data) const = 0; + + // This method must be implemented in any subclasses and it must try to + // read one "Pair" at the offset pointed to by the "hash_data_offset_ptr" + // parameter. This offset should be updated as bytes are consumed and + // a value "Result" enum should be returned. If the "name" matches the + // full name for the "pair.key" (which must be filled in by this call), + // then the HashData in the pair ("pair.value") should be extracted and + // filled in and "eResultKeyMatch" should be returned. If "name" doesn't + // match this string for the key, then "eResultKeyMismatch" should be + // returned and all data for the current HashData must be consumed or + // skipped and the "hash_data_offset_ptr" offset needs to be updated to + // point to the next HashData. If the end of the HashData objects for + // a given hash value have been reached, then "eResultEndOfHashData" + // should be returned. If anything else goes wrong during parsing, + // return "eResultError" and the corresponding "Find()" function will + // be canceled and return false. + virtual Result GetHashDataForName(const char *name, + lldb::offset_t *hash_data_offset_ptr, + Pair &pair) const = 0; + + const HeaderType &GetHeader() { return m_header; } + + void ForEach( + std::function const &callback) const { + const size_t num_hash_offsets = m_header.hashes_count; + for (size_t i = 0; i < num_hash_offsets; ++i) { + uint32_t hash_data_offset = GetHashDataOffset(i); + if (hash_data_offset != UINT32_MAX) { + HashData hash_data; + if (ReadHashData(hash_data_offset, hash_data)) { + // If the callback returns false, then we are done and should stop + if (callback(hash_data) == false) + return; + } + } + } + } + + protected: + // Implementation agnostic information + HeaderType m_header; + const uint32_t *m_hash_indexes; + const uint32_t *m_hash_values; + const uint32_t *m_hash_offsets; + }; +}; + +#endif // liblldb_MappedHash_h_ diff --git a/include/lldb/Core/Module.h b/include/lldb/Core/Module.h new file mode 100644 index 000000000..2ffe57ad8 --- /dev/null +++ b/include/lldb/Core/Module.h @@ -0,0 +1,1220 @@ +//===-- 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/Address.h" // for Address +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/ModuleSpec.h" // for ModuleSpec +#include "lldb/Symbol/SymbolContextScope.h" +#include "lldb/Symbol/TypeSystem.h" +#include "lldb/Target/PathMappingList.h" +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" // for Status +#include "lldb/Utility/UUID.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for LanguageType, SymbolType +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" // for addr_t, offset_t + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Chrono.h" + +#include +#include // for enable_shared_from_this +#include +#include // for size_t +#include // for uint32_t, uint64_t +#include +#include + +namespace lldb_private { +class CompilerDeclContext; +} +namespace lldb_private { +class Function; +} +namespace lldb_private { +class Log; +} +namespace lldb_private { +class ObjectFile; +} +namespace lldb_private { +class RegularExpression; +} +namespace lldb_private { +class SectionList; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class Symbol; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class SymbolContextList; +} +namespace lldb_private { +class SymbolFile; +} +namespace lldb_private { +class SymbolVendor; +} +namespace lldb_private { +class Symtab; +} +namespace lldb_private { +class Target; +} +namespace lldb_private { +class TypeList; +} +namespace lldb_private { +class TypeMap; +} +namespace lldb_private { +class VariableList; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Module Module.h "lldb/Core/Module.h" +/// @brief A class that describes an executable image and its associated +/// object and symbol files. +/// +/// The module is designed to be able to select a single slice of an +/// executable image as it would appear on disk and during program +/// execution. +/// +/// Modules control when and if information is parsed according to which +/// accessors are called. For example the object file (ObjectFile) +/// representation will only be parsed if the object file is requested +/// using the Module::GetObjectFile() is called. The debug symbols +/// will only be parsed if the symbol vendor (SymbolVendor) is +/// requested using the Module::GetSymbolVendor() is called. +/// +/// The module will parse more detailed information as more queries are +/// made. +//---------------------------------------------------------------------- +class Module : public std::enable_shared_from_this, + public SymbolContextScope { +public: + // Static functions that can track the lifetime of module objects. + // This is handy because we might have Module objects that are in + // shared pointers that aren't in the global module list (from + // ModuleList). If this is the case we need to know about it. + // The modules in the global list maintained by these functions + // can be viewed using the "target modules list" command using the + // "--global" (-g for short). + static size_t GetNumberAllocatedModules(); + + static Module *GetAllocatedModuleAtIndex(size_t idx); + + static std::recursive_mutex &GetAllocationModuleCollectionMutex(); + + //------------------------------------------------------------------ + /// Construct with file specification and architecture. + /// + /// Clients that wish to share modules with other targets should + /// use ModuleList::GetSharedModule(). + /// + /// @param[in] file_spec + /// The file specification for the on disk representation 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 = nullptr, + lldb::offset_t object_offset = 0, + const llvm::sys::TimePoint<> &object_mod_time = llvm::sys::TimePoint<>()); + + Module(const ModuleSpec &module_spec); + + static lldb::ModuleSP + CreateJITModule(const lldb::ObjectFileJITDelegateSP &delegate_sp); + + //------------------------------------------------------------------ + /// Destructor. + //------------------------------------------------------------------ + ~Module() override; + + bool MatchesModuleSpec(const ModuleSpec &module_ref); + + //------------------------------------------------------------------ + /// Set the load address for all sections in a module to be the + /// file address plus \a slide. + /// + /// Many times a module will be loaded in a target with a constant + /// offset applied to all top level sections. This function can + /// set the load address for all top level sections to be the + /// section file address + offset. + /// + /// @param[in] target + /// The target in which to apply the section load addresses. + /// + /// @param[in] value + /// if \a value_is_offset is true, then value is the offset to + /// apply to all file addresses for all top level sections in + /// the object file as each section load address is being set. + /// If \a value_is_offset is false, then "value" is the new + /// absolute base address for the image. + /// + /// @param[in] value_is_offset + /// If \b true, then \a value is an offset to apply to each + /// file address of each top level section. + /// If \b false, then \a value is the image base address that + /// will be used to rigidly slide all loadable sections. + /// + /// @param[out] changed + /// If any section load addresses were changed in \a target, + /// then \a changed will be set to \b true. Else \a changed + /// will be set to false. This allows this function to be + /// called multiple times on the same module for the same + /// target. If the module hasn't moved, then \a changed will + /// be false and no module updated notification will need to + /// be sent out. + /// + /// @return + /// /b True if any sections were successfully loaded in \a target, + /// /b false otherwise. + //------------------------------------------------------------------ + bool SetLoadAddress(Target &target, lldb::addr_t value, bool value_is_offset, + bool &changed); + + //------------------------------------------------------------------ + /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*) + /// + /// @see SymbolContextScope + //------------------------------------------------------------------ + void CalculateSymbolContext(SymbolContext *sc) override; + + lldb::ModuleSP CalculateSymbolContextModule() override; + + void + GetDescription(Stream *s, + lldb::DescriptionLevel level = lldb::eDescriptionLevelFull); + + //------------------------------------------------------------------ + /// Get the module path and object name. + /// + /// Modules can refer to object files. In this case the specification + /// is simple and would return the path to the file: + /// + /// "/usr/lib/foo.dylib" + /// + /// Modules can be .o files inside of a BSD archive (.a file). In + /// this case, the object specification will look like: + /// + /// "/usr/lib/foo.a(bar.o)" + /// + /// There are many places where logging wants to log this fully + /// qualified specification, so we centralize this functionality + /// here. + /// + /// @return + /// The object path + object name if there is one. + //------------------------------------------------------------------ + std::string GetSpecificationDescription() const; + + //------------------------------------------------------------------ + /// Dump a description of this object to a Stream. + /// + /// Dump a description of the contents of this object to the + /// supplied stream \a s. The dumped content will be only what has + /// been loaded or parsed up to this point at which this function + /// is called, so this is a good way to see what has been parsed + /// in a module. + /// + /// @param[in] s + /// The stream to which to dump the object description. + //------------------------------------------------------------------ + void Dump(Stream *s); + + //------------------------------------------------------------------ + /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*) + /// + /// @see SymbolContextScope + //------------------------------------------------------------------ + void DumpSymbolContext(Stream *s) override; + + //------------------------------------------------------------------ + /// Find a symbol in the object file's symbol table. + /// + /// @param[in] name + /// The name of the symbol that we are looking for. + /// + /// @param[in] symbol_type + /// If set to eSymbolTypeAny, find a symbol of any type that + /// has a name that matches \a name. If set to any other valid + /// SymbolType enumeration value, then search only for + /// symbols that match \a symbol_type. + /// + /// @return + /// Returns a valid symbol pointer if a symbol was found, + /// nullptr 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 ®ex, + lldb::SymbolType symbol_type, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// Find a function symbols in the object file's symbol table. + /// + /// @param[in] name + /// The name of the symbol that we are looking for. + /// + /// @param[in] name_type_mask + /// A mask that has one or more bitwise OR'ed values from the + /// lldb::FunctionNameType enumeration type that indicate what + /// kind of names we are looking for. + /// + /// @param[out] sc_list + /// A list to append any matching symbol contexts to. + /// + /// @return + /// The number of symbol contexts that were added to \a sc_list + //------------------------------------------------------------------ + size_t FindFunctionSymbols(const ConstString &name, uint32_t name_type_mask, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// Find compile units by partial or full path. + /// + /// Finds all compile units that match \a path in all of the modules + /// and returns the results in \a sc_list. + /// + /// @param[in] path + /// The name of the function we are looking for. + /// + /// @param[in] append + /// If \b true, then append any compile units that were found + /// to \a sc_list. If \b false, then the \a sc_list is cleared + /// and the contents of \a sc_list are replaced. + /// + /// @param[out] sc_list + /// A symbol context list that gets filled in with all of the + /// matches. + /// + /// @return + /// The number of matches added to \a sc_list. + //------------------------------------------------------------------ + size_t FindCompileUnits(const FileSpec &path, bool append, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// Find functions by name. + /// + /// If the function is an inlined function, it will have a block, + /// representing the inlined function, and the function will be the + /// containing function. If it is not inlined, then the block will + /// be NULL. + /// + /// @param[in] name + /// The name of the compile unit we are looking for. + /// + /// @param[in] namespace_decl + /// If valid, a namespace to search in. + /// + /// @param[in] name_type_mask + /// A bit mask of bits that indicate what kind of names should + /// be used when doing the lookup. Bits include fully qualified + /// names, base names, C++ methods, or ObjC selectors. + /// See FunctionNameType for more details. + /// + /// @param[in] append + /// If \b true, any matches will be appended to \a sc_list, else + /// matches replace the contents of \a sc_list. + /// + /// @param[out] sc_list + /// A symbol context list that gets filled in with all of the + /// matches. + /// + /// @return + /// The number of matches added to \a sc_list. + //------------------------------------------------------------------ + size_t FindFunctions(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + uint32_t name_type_mask, bool symbols_ok, + bool inlines_ok, bool append, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// Find functions by name. + /// + /// If the function is an inlined function, it will have a block, + /// representing the inlined function, and the function will be the + /// containing function. If it is not inlined, then the block will + /// be NULL. + /// + /// @param[in] regex + /// A regular expression to use when matching the name. + /// + /// @param[in] append + /// If \b true, any matches will be appended to \a sc_list, else + /// matches replace the contents of \a sc_list. + /// + /// @param[out] sc_list + /// A symbol context list that gets filled in with all of the + /// matches. + /// + /// @return + /// The number of matches added to \a sc_list. + //------------------------------------------------------------------ + size_t FindFunctions(const RegularExpression ®ex, bool symbols_ok, + bool inlines_ok, bool append, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// Find addresses by file/line + /// + /// @param[in] target_sp + /// The target the addresses are desired for. + /// + /// @param[in] file + /// Source file to locate. + /// + /// @param[in] line + /// Source line to locate. + /// + /// @param[in] function + /// Optional filter function. Addresses within this function will be + /// added to the 'local' list. All others will be added to the 'extern' + /// list. + /// + /// @param[out] output_local + /// All matching addresses within 'function' + /// + /// @param[out] output_extern + /// All matching addresses not within 'function' + void FindAddressesForLine(const lldb::TargetSP target_sp, + const FileSpec &file, uint32_t line, + Function *function, + std::vector
&output_local, + std::vector
&output_extern); + + //------------------------------------------------------------------ + /// Find global and static variables by name. + /// + /// @param[in] name + /// The name of the global or static variable we are looking + /// for. + /// + /// @param[in] parent_decl_ctx + /// If valid, a decl context that results must exist within + /// + /// @param[in] append + /// If \b true, any matches will be appended to \a + /// variable_list, else matches replace the contents of + /// \a variable_list. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a + /// max_matches. Specify UINT32_MAX to get all possible matches. + /// + /// @param[in] variable_list + /// A list of variables that gets the matches appended to (if + /// \a append it \b true), or replace (if \a append is \b false). + /// + /// @return + /// The number of matches added to \a variable_list. + //------------------------------------------------------------------ + size_t FindGlobalVariables(const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, + bool append, size_t max_matches, + VariableList &variable_list); + + //------------------------------------------------------------------ + /// Find global and static variables by regular expression. + /// + /// @param[in] regex + /// A regular expression to use when matching the name. + /// + /// @param[in] append + /// If \b true, any matches will be appended to \a + /// variable_list, else matches replace the contents of + /// \a variable_list. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a + /// max_matches. Specify UINT32_MAX to get all possible matches. + /// + /// @param[in] variable_list + /// A list of variables that gets the matches appended to (if + /// \a append it \b true), or replace (if \a append is \b false). + /// + /// @return + /// The number of matches added to \a variable_list. + //------------------------------------------------------------------ + size_t FindGlobalVariables(const RegularExpression ®ex, bool append, + size_t max_matches, VariableList &variable_list); + + //------------------------------------------------------------------ + /// Find types by name. + /// + /// Type lookups in modules go through the SymbolVendor (which will + /// use one or more SymbolFile subclasses). The SymbolFile needs to + /// be able to lookup types by basename and not the fully qualified + /// typename. This allows the type accelerator tables to stay small, + /// even with heavily templatized C++. The type search will then + /// narrow down the search results. If "exact_match" is true, then + /// the type search will only match exact type name matches. If + /// "exact_match" is false, the type will match as long as the base + /// typename matches and as long as any immediate containing + /// namespaces/class scopes that are specified match. So to search + /// for a type "d" in "b::c", the name "b::c::d" can be specified + /// and it will match any class/namespace "b" which contains a + /// class/namespace "c" which contains type "d". We do this to + /// allow users to not always have to specify complete scoping on + /// all expressions, but it also allows for exact matching when + /// required. + /// + /// @param[in] sc + /// A symbol context that scopes where to extract a type list + /// from. + /// + /// @param[in] type_name + /// The name of the type we are looking for that is a fully + /// or partially qualified type name. + /// + /// @param[in] exact_match + /// If \b true, \a type_name is fully qualified and must match + /// exactly. If \b false, \a type_name is a partially qualified + /// name where the leading namespaces or classes can be + /// omitted to make finding types that a user may type + /// easier. + /// + /// @param[out] type_list + /// A type list gets populated with any matches. + /// + /// @return + /// The number of matches added to \a type_list. + //------------------------------------------------------------------ + size_t + FindTypes(const SymbolContext &sc, const ConstString &type_name, + bool exact_match, size_t max_matches, + llvm::DenseSet &searched_symbol_files, + TypeList &types); + + lldb::TypeSP FindFirstType(const SymbolContext &sc, + const ConstString &type_name, bool exact_match); + + //------------------------------------------------------------------ + /// Find types by name that are in a namespace. This function is + /// used by the expression parser when searches need to happen in + /// an exact namespace scope. + /// + /// @param[in] sc + /// A symbol context that scopes where to extract a type list + /// from. + /// + /// @param[in] type_name + /// The name of a type within a namespace that should not include + /// any qualifying namespaces (just a type basename). + /// + /// @param[in] namespace_decl + /// The namespace declaration that this type must exist in. + /// + /// @param[out] type_list + /// A type list gets populated with any matches. + /// + /// @return + /// The number of matches added to \a type_list. + //------------------------------------------------------------------ + size_t FindTypesInNamespace(const SymbolContext &sc, + const ConstString &type_name, + const CompilerDeclContext *parent_decl_ctx, + size_t max_matches, TypeList &type_list); + + //------------------------------------------------------------------ + /// Get const accessor for the module architecture. + /// + /// @return + /// A const reference to the architecture object. + //------------------------------------------------------------------ + const ArchSpec &GetArchitecture() const; + + //------------------------------------------------------------------ + /// Get const accessor for the module file specification. + /// + /// This function returns the file for the module on the host system + /// that is running LLDB. This can differ from the path on the + /// platform since we might be doing remote debugging. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + const FileSpec &GetFileSpec() const { return m_file; } + + //------------------------------------------------------------------ + /// Get accessor for the module platform file specification. + /// + /// Platform file refers to the path of the module as it is known on + /// the remote system on which it is being debugged. For local + /// debugging this is always the same as Module::GetFileSpec(). But + /// remote debugging might mention a file "/usr/lib/liba.dylib" + /// which might be locally downloaded and cached. In this case the + /// platform file could be something like: + /// "/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib" + /// The file could also be cached in a local developer kit directory. + /// + /// @return + /// A const reference to the file specification object. + //------------------------------------------------------------------ + const FileSpec &GetPlatformFileSpec() const { + if (m_platform_file) + return m_platform_file; + return m_file; + } + + void SetPlatformFileSpec(const FileSpec &file) { m_platform_file = file; } + + const FileSpec &GetRemoteInstallFileSpec() const { + return m_remote_install_file; + } + + void SetRemoteInstallFileSpec(const FileSpec &file) { + m_remote_install_file = file; + } + + const FileSpec &GetSymbolFileFileSpec() const { return m_symfile_spec; } + + void PreloadSymbols(); + + void SetSymbolFileFileSpec(const FileSpec &file); + + const llvm::sys::TimePoint<> &GetModificationTime() const { + return m_mod_time; + } + + const llvm::sys::TimePoint<> &GetObjectModificationTime() const { + return m_object_mod_time; + } + + void SetObjectModificationTime(const llvm::sys::TimePoint<> &mod_time) { + m_mod_time = mod_time; + } + + //------------------------------------------------------------------ + /// Tells whether this module is capable of being the main executable + /// for a process. + /// + /// @return + /// \b true if it is, \b false otherwise. + //------------------------------------------------------------------ + bool IsExecutable(); + + //------------------------------------------------------------------ + /// Tells whether this module has been loaded in the target passed in. + /// This call doesn't distinguish between whether the module is loaded + /// by the dynamic loader, or by a "target module add" type call. + /// + /// @param[in] target + /// The target to check whether this is loaded in. + /// + /// @return + /// \b true if it is, \b false otherwise. + //------------------------------------------------------------------ + bool IsLoadedInTarget(Target *target); + + bool LoadScriptingResourceInTarget(Target *target, Status &error, + Stream *feedback_stream = nullptr); + + //------------------------------------------------------------------ + /// Get the number of compile units for this module. + /// + /// @return + /// The number of compile units that the symbol vendor plug-in + /// finds. + //------------------------------------------------------------------ + size_t GetNumCompileUnits(); + + lldb::CompUnitSP GetCompileUnitAtIndex(size_t idx); + + const ConstString &GetObjectName() const; + + uint64_t GetObjectOffset() const { return m_object_offset; } + + //------------------------------------------------------------------ + /// Get the object file representation for the current architecture. + /// + /// If the object file has not been located or parsed yet, this + /// function will find the best ObjectFile plug-in that can parse + /// Module::m_file. + /// + /// @return + /// If Module::m_file does not exist, or no plug-in was found + /// that can parse the file, or the object file doesn't contain + /// the current architecture in Module::m_arch, nullptr will be + /// returned, else a valid object file interface will be + /// returned. The returned pointer is owned by this object and + /// remains valid as long as the object is around. + //------------------------------------------------------------------ + virtual ObjectFile *GetObjectFile(); + + //------------------------------------------------------------------ + /// Get the unified section list for the module. This is the section + /// list created by the module's object file and any debug info and + /// symbol files created by the symbol vendor. + /// + /// If the symbol vendor has not been loaded yet, this function + /// will return the section list for the object file. + /// + /// @return + /// Unified module section list. + //------------------------------------------------------------------ + virtual SectionList *GetSectionList(); + + //------------------------------------------------------------------ + /// Notify the module that the file addresses for the Sections have + /// been updated. + /// + /// If the Section file addresses for a module are updated, this + /// method should be called. Any parts of the module, object file, + /// or symbol file that has cached those file addresses must invalidate + /// or update its cache. + //------------------------------------------------------------------ + virtual void SectionFileAddressesChanged(); + + uint32_t GetVersion(uint32_t *versions, uint32_t num_versions); + + //------------------------------------------------------------------ + /// Load an object file from memory. + /// + /// If available, the size of the object file in memory may be + /// passed to avoid additional round trips to process memory. + /// If the size is not provided, a default value is used. This + /// value should be large enough to enable the ObjectFile plugins + /// to read the header of the object file without going back to the + /// process. + /// + /// @return + /// The object file loaded from memory or nullptr, if the operation + /// failed (see the `error` for more information in that case). + //------------------------------------------------------------------ + ObjectFile *GetMemoryObjectFile(const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr, Status &error, + size_t size_to_read = 512); + //------------------------------------------------------------------ + /// 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, nullptr will + /// be returned, else a valid symbol vendor plug-in interface + /// will be returned. The returned pointer is owned by this + /// object and remains valid as long as the object is around. + //------------------------------------------------------------------ + virtual SymbolVendor * + GetSymbolVendor(bool can_create = true, + lldb_private::Stream *feedback_strm = nullptr); + + //------------------------------------------------------------------ + /// Get accessor the type list for this module. + /// + /// @return + /// A valid type list pointer, or nullptr if there is no valid + /// symbol vendor for this module. + //------------------------------------------------------------------ + TypeList *GetTypeList(); + + //------------------------------------------------------------------ + /// Get a pointer to the UUID value contained in this object. + /// + /// If the executable image file doesn't not have a UUID value built + /// into the file format, an MD5 checksum of the entire file, or + /// slice of the file for the current architecture should be used. + /// + /// @return + /// A const pointer to the internal copy of the UUID value in + /// this module if this module has a valid UUID value, NULL + /// otherwise. + //------------------------------------------------------------------ + const lldb_private::UUID &GetUUID(); + + //------------------------------------------------------------------ + /// A debugging function that will cause everything in a module to + /// be parsed. + /// + /// All compile units will be parsed, 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 + /// resulting 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); + + //------------------------------------------------------------------ + /// Resolve the symbol context for the given address. + /// + /// Tries to resolve the matching symbol context based on a lookup + /// from the current symbol vendor. If the lazy lookup fails, + /// an attempt is made to parse the eh_frame section to handle + /// stripped symbols. If this fails, an attempt is made to resolve + /// the symbol to the previous address to handle the case of a + /// function with a tail call. + /// + /// Use properties of the modified SymbolContext to inspect any + /// resolved target, module, compilation unit, symbol, function, + /// function block or line entry. Use the return value to determine + /// which of these properties have been modified. + /// + /// @param[in] so_addr + /// A load address to resolve. + /// + /// @param[in] resolve_scope + /// The scope that should be resolved (see SymbolContext::Scope). + /// A combination of flags from the enumeration SymbolContextItem + /// requesting a resolution depth. Note that the flags that are + /// actually resolved may be a superset of the requested flags. + /// For instance, eSymbolContextSymbol requires resolution of + /// eSymbolContextModule, and eSymbolContextFunction requires + /// eSymbolContextSymbol. + /// + /// @param[out] sc + /// The SymbolContext that is modified based on symbol resolution. + /// + /// @param[in] resolve_tail_call_address + /// Determines if so_addr should resolve to a symbol in the case + /// of a function whose last instruction is a call. In this case, + /// the PC can be one past the address range of the function. + /// + /// @return + /// The scope that has been resolved (see SymbolContext::Scope). + /// + /// @see SymbolContext::Scope + //------------------------------------------------------------------ + uint32_t + ResolveSymbolContextForAddress(const Address &so_addr, uint32_t resolve_scope, + SymbolContext &sc, + bool resolve_tail_call_address = false); + + //------------------------------------------------------------------ + /// Resolve items in the symbol context for a given file and line. + /// + /// Tries to resolve \a file_path and \a line to a list of matching + /// symbol contexts. + /// + /// The line table entries contains addresses that can be used to + /// further resolve the values in each match: the function, block, + /// symbol. Care should be taken to minimize the amount of + /// information that is requested to only what is needed -- + /// typically the module, compile unit, line table and line table + /// entry are sufficient. + /// + /// @param[in] file_path + /// A path to a source file to match. If \a file_path does not + /// specify a directory, then this query will match all files + /// whose base filename matches. If \a file_path does specify + /// a directory, the fullpath to the file must match. + /// + /// @param[in] line + /// The source line to match, or zero if just the compile unit + /// should be resolved. + /// + /// @param[in] check_inlines + /// Check for inline file and line number matches. This option + /// should be used sparingly as it will cause all line tables + /// for every compile unit to be parsed and searched for + /// matching inline file entries. + /// + /// @param[in] resolve_scope + /// The scope that should be resolved (see + /// SymbolContext::Scope). + /// + /// @param[out] sc_list + /// A symbol context list that gets matching symbols contexts + /// appended to. + /// + /// @return + /// The number of matches that were added to \a sc_list. + /// + /// @see SymbolContext::Scope + //------------------------------------------------------------------ + uint32_t ResolveSymbolContextForFilePath(const char *file_path, uint32_t line, + bool check_inlines, + uint32_t resolve_scope, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// Resolve items in the symbol context for a given file and line. + /// + /// Tries to resolve \a file_spec and \a line to a list of matching + /// symbol contexts. + /// + /// The line table entries contains addresses that can be used to + /// further resolve the values in each match: the function, block, + /// symbol. Care should be taken to minimize the amount of + /// information that is requested to only what is needed -- + /// typically the module, compile unit, line table and line table + /// entry are sufficient. + /// + /// @param[in] file_spec + /// A file spec to a source file to match. If \a file_path does + /// not specify a directory, then this query will match all + /// files whose base filename matches. If \a file_path does + /// specify a directory, the fullpath to the file must match. + /// + /// @param[in] line + /// The source line to match, or zero if just the compile unit + /// should be resolved. + /// + /// @param[in] check_inlines + /// Check for inline file and line number matches. This option + /// should be used sparingly as it will cause all line tables + /// for every compile unit to be parsed and searched for + /// matching inline file entries. + /// + /// @param[in] resolve_scope + /// The scope that should be resolved (see + /// SymbolContext::Scope). + /// + /// @param[out] sc_list + /// A symbol context list that gets filled in with all of the + /// matches. + /// + /// @return + /// A integer that contains SymbolContext::Scope bits set for + /// each item that was successfully resolved. + /// + /// @see SymbolContext::Scope + //------------------------------------------------------------------ + uint32_t ResolveSymbolContextsForFileSpec(const FileSpec &file_spec, + uint32_t line, bool check_inlines, + uint32_t resolve_scope, + SymbolContextList &sc_list); + + void SetFileSpecAndObjectName(const FileSpec &file, + const ConstString &object_name); + + bool GetIsDynamicLinkEditor(); + + TypeSystem *GetTypeSystemForLanguage(lldb::LanguageType language); + + // Special error functions that can do printf style formatting that will + // prepend the message with + // something appropriate for this module (like the architecture, path and + // object name (if any)). + // This centralizes code so that everyone doesn't need to format their error + // and log messages on + // their own and keeps the output a bit more consistent. + void LogMessage(Log *log, const char *format, ...) + __attribute__((format(printf, 3, 4))); + + void LogMessageVerboseBacktrace(Log *log, const char *format, ...) + __attribute__((format(printf, 3, 4))); + + void ReportWarning(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + void ReportError(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + // Only report an error once when the module is first detected to be modified + // so we don't spam the console with many messages. + void ReportErrorIfModifyDetected(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + //------------------------------------------------------------------ + // Return true if the file backing this module has changed since the + // module was originally created since we saved the initial file + // modification time when the module first gets created. + //------------------------------------------------------------------ + bool FileHasChanged() const; + + //------------------------------------------------------------------ + // SymbolVendor, SymbolFile and ObjectFile member objects should + // lock the module mutex to avoid deadlocks. + //------------------------------------------------------------------ + std::recursive_mutex &GetMutex() const { return m_mutex; } + + PathMappingList &GetSourceMappingList() { return m_source_mappings; } + + const PathMappingList &GetSourceMappingList() const { + return m_source_mappings; + } + + //------------------------------------------------------------------ + /// Finds a source file given a file spec using the module source + /// path remappings (if any). + /// + /// Tries to resolve \a orig_spec by checking the module source path + /// remappings. It makes sure the file exists, so this call can be + /// expensive if the remappings are on a network file system, so + /// use this function sparingly (not in a tight debug info parsing + /// loop). + /// + /// @param[in] orig_spec + /// The original source file path to try and remap. + /// + /// @param[out] new_spec + /// The newly remapped filespec that is guaranteed to exist. + /// + /// @return + /// /b true if \a orig_spec was successfully located and + /// \a new_spec is filled in with an existing file spec, + /// \b false otherwise. + //------------------------------------------------------------------ + bool FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const; + + //------------------------------------------------------------------ + /// Remaps a source file given \a path into \a new_path. + /// + /// Remaps \a path if any source remappings match. This function + /// does NOT stat the file system so it can be used in tight loops + /// where debug info is being parsed. + /// + /// @param[in] path + /// The original source file path to try and remap. + /// + /// @param[out] new_path + /// The newly remapped filespec that is may or may not exist. + /// + /// @return + /// /b true if \a path was successfully located and \a new_path + /// is filled in with a new source path, \b false otherwise. + //------------------------------------------------------------------ + bool RemapSourceFile(llvm::StringRef path, std::string &new_path) const; + bool RemapSourceFile(const char *, std::string &) const = delete; + + //------------------------------------------------------------------ + /// Loads this module to memory. + /// + /// Loads the bits needed to create an executable image to the memory. + /// It is useful with bare-metal targets where target does not have the + /// ability to start a process itself. + /// + /// @param[in] target + /// Target where to load the module. + /// + /// @return + //------------------------------------------------------------------ + Status LoadInMemory(Target &target, bool set_pc); + + //---------------------------------------------------------------------- + /// @class LookupInfo Module.h "lldb/Core/Module.h" + /// @brief A class that encapsulates name lookup information. + /// + /// Users can type a wide variety of partial names when setting + /// breakpoints by name or when looking for functions by name. + /// SymbolVendor and SymbolFile objects are only required to implement + /// name lookup for function basenames and for fully mangled names. + /// This means if the user types in a partial name, we must reduce this + /// to a name lookup that will work with all SymbolFile objects. So we + /// might reduce a name lookup to look for a basename, and then prune + /// out any results that don't match. + /// + /// The "m_name" member variable represents the name as it was typed + /// by the user. "m_lookup_name" will be the name we actually search + /// for through the symbol or objects files. Lanaguage is included in + /// case we need to filter results by language at a later date. The + /// "m_name_type_mask" member variable tells us what kinds of names we + /// are looking for and can help us prune out unwanted results. + /// + /// Function lookups are done in Module.cpp, ModuleList.cpp and in + /// BreakpointResolverName.cpp and they all now use this class to do + /// lookups correctly. + //---------------------------------------------------------------------- + class LookupInfo { + public: + LookupInfo() + : m_name(), m_lookup_name(), m_language(lldb::eLanguageTypeUnknown), + m_name_type_mask(0), m_match_name_after_lookup(false) {} + + LookupInfo(const ConstString &name, uint32_t name_type_mask, + lldb::LanguageType language); + + const ConstString &GetName() const { return m_name; } + + void SetName(const ConstString &name) { m_name = name; } + + const ConstString &GetLookupName() const { return m_lookup_name; } + + void SetLookupName(const ConstString &name) { m_lookup_name = name; } + + uint32_t GetNameTypeMask() const { return m_name_type_mask; } + + void SetNameTypeMask(uint32_t mask) { m_name_type_mask = mask; } + + void Prune(SymbolContextList &sc_list, size_t start_idx) const; + + protected: + ConstString m_name; ///< What the user originally typed + ConstString m_lookup_name; ///< The actual name will lookup when calling in + ///the object or symbol file + lldb::LanguageType + m_language; ///< Limit matches to only be for this language + uint32_t m_name_type_mask; ///< One or more bits from lldb::FunctionNameType + ///that indicate what kind of names we are + ///looking for + bool m_match_name_after_lookup; ///< If \b true, then demangled names that + ///match will need to contain "m_name" in + ///order to be considered a match + }; + +protected: + //------------------------------------------------------------------ + // Member Variables + //------------------------------------------------------------------ + mutable std::recursive_mutex m_mutex; ///< A mutex to keep this object happy + ///in multi-threaded environments. + + /// The modification time for this module when it was created. + llvm::sys::TimePoint<> m_mod_time; + + 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). + FileSpec m_platform_file; ///< The path to the module on the platform on which + ///it is being debugged + FileSpec m_remote_install_file; ///< If set when debugging on remote + ///platforms, this module will be installed at + ///this location + FileSpec m_symfile_spec; ///< If this path is valid, then this is the file + ///that _will_ be used as the symbol file for this + ///module + ConstString m_object_name; ///< The name an object within this module that is + ///selected, or empty of the module is represented + ///by \a m_file. + uint64_t m_object_offset; + llvm::sys::TimePoint<> m_object_mod_time; + lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file + ///parser for this module as it may or may + ///not be shared with the SymbolFile + lldb::SymbolVendorUP + m_symfile_ap; ///< A pointer to the symbol vendor for this module. + std::vector + m_old_symfiles; ///< If anyone calls Module::SetSymbolFileFileSpec() and + ///changes the symbol file, + ///< we need to keep all old symbol files around in case anyone has type + ///references to them + TypeSystemMap m_type_system_map; ///< A map of any type systems associated + ///with this module + PathMappingList m_source_mappings; ///< Module specific source remappings for + ///when you have debug info for a module + ///that doesn't match where the sources + ///currently are + lldb::SectionListUP m_sections_ap; ///< Unified section list for module that + ///is used by the ObjectFile and and + ///ObjectFile instances for the debug info + + std::atomic m_did_load_objfile{false}; + std::atomic m_did_load_symbol_vendor{false}; + std::atomic m_did_parse_uuid{false}; + mutable bool m_file_has_changed : 1, + m_first_file_changed_log : 1; /// See if the module was modified after it + /// was initially opened. + + //------------------------------------------------------------------ + /// Resolve a file or load virtual address. + /// + /// Tries to resolve \a vm_addr as a file address (if \a + /// vm_addr_is_file_addr is true) or as a load address if \a + /// vm_addr_is_file_addr is false) in the symbol vendor. + /// \a resolve_scope indicates what clients wish to resolve + /// and can be used to limit the scope of what is parsed. + /// + /// @param[in] vm_addr + /// The load virtual address to resolve. + /// + /// @param[in] vm_addr_is_file_addr + /// If \b true, \a vm_addr is a file address, else \a vm_addr + /// if a load address. + /// + /// @param[in] resolve_scope + /// The scope that should be resolved (see + /// SymbolContext::Scope). + /// + /// @param[out] so_addr + /// The section offset based address that got resolved if + /// any bits are returned. + /// + /// @param[out] sc + // The symbol context that has objects filled in. Each bit + /// in the \a resolve_scope pertains to a member in the \a sc. + /// + /// @return + /// A integer that contains SymbolContext::Scope bits set for + /// each item that was successfully resolved. + /// + /// @see SymbolContext::Scope + //------------------------------------------------------------------ + uint32_t ResolveSymbolContextForAddress(lldb::addr_t vm_addr, + bool vm_addr_is_file_addr, + uint32_t resolve_scope, + Address &so_addr, SymbolContext &sc); + + void SymbolIndicesToSymbolContextList(Symtab *symtab, + std::vector &symbol_indexes, + SymbolContextList &sc_list); + + bool SetArchitecture(const ArchSpec &new_arch); + + SectionList *GetUnifiedSectionList(); + + friend class ModuleList; + friend class ObjectFile; + friend class SymbolFile; + +private: + Module(); // Only used internally by CreateJITModule () + + size_t FindTypes_Impl( + const SymbolContext &sc, const ConstString &name, + const CompilerDeclContext *parent_decl_ctx, bool append, + size_t max_matches, + llvm::DenseSet &searched_symbol_files, + TypeMap &types); + + DISALLOW_COPY_AND_ASSIGN(Module); +}; + +} // namespace lldb_private + +#endif // liblldb_Module_h_ diff --git a/include/lldb/Core/ModuleChild.h b/include/lldb/Core/ModuleChild.h new file mode 100644 index 000000000..8f2985c81 --- /dev/null +++ b/include/lldb/Core/ModuleChild.h @@ -0,0 +1,85 @@ +//===-- 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-forward.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class ModuleChild ModuleChild.h "lldb/Core/ModuleChild.h" +/// @brief A mix in class that contains a pointer back to the module +/// that owns the object which inherits from it. +//---------------------------------------------------------------------- +class ModuleChild { +public: + //------------------------------------------------------------------ + /// Construct with owning module. + /// + /// @param[in] module + /// The module that owns the object that inherits from this + /// class. + //------------------------------------------------------------------ + ModuleChild(const lldb::ModuleSP &module_sp); + + //------------------------------------------------------------------ + /// Copy constructor. + /// + /// @param[in] rhs + /// A const ModuleChild class reference to copy. + //------------------------------------------------------------------ + ModuleChild(const ModuleChild &rhs); + + //------------------------------------------------------------------ + /// Destructor. + //------------------------------------------------------------------ + ~ModuleChild(); + + //------------------------------------------------------------------ + /// Assignment operator. + /// + /// @param[in] rhs + /// A const ModuleChild class reference to copy. + /// + /// @return + /// A const reference to this object. + //------------------------------------------------------------------ + const ModuleChild &operator=(const ModuleChild &rhs); + + //------------------------------------------------------------------ + /// Get const accessor for the module pointer. + /// + /// @return + /// A const pointer to the module that owns the object that + /// inherits from this class. + //------------------------------------------------------------------ + lldb::ModuleSP GetModule() const; + + //------------------------------------------------------------------ + /// Set accessor for the module pointer. + /// + /// @param[in] module + /// A new module that owns the object that inherits from this + /// class. + //------------------------------------------------------------------ + void SetModule(const lldb::ModuleSP &module_sp); + +protected: + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + lldb::ModuleWP m_module_wp; ///< The Module that owns the object that inherits + ///< from this class. +}; + +} // namespace lldb_private + +#endif // liblldb_ModuleChild_h_ diff --git a/include/lldb/Core/ModuleList.h b/include/lldb/Core/ModuleList.h new file mode 100644 index 000000000..4b637c9b0 --- /dev/null +++ b/include/lldb/Core/ModuleList.h @@ -0,0 +1,597 @@ +//===-- 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 "lldb/Core/Address.h" // for Address +#include "lldb/Core/ModuleSpec.h" // for ModuleSpec +#include "lldb/Utility/FileSpec.h" // for FileSpec +#include "lldb/Utility/Iterable.h" +#include "lldb/Utility/Status.h" // for Status +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +#include "llvm/ADT/DenseSet.h" + +#include +#include +#include +#include + +#include // for size_t +#include // for uint32_t + +namespace lldb_private { +class ConstString; +} +namespace lldb_private { +class FileSpecList; +} +namespace lldb_private { +class Function; +} +namespace lldb_private { +class Log; +} +namespace lldb_private { +class Module; +} +namespace lldb_private { +class RegularExpression; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class SymbolContextList; +} +namespace lldb_private { +class SymbolFile; +} +namespace lldb_private { +class Target; +} +namespace lldb_private { +class TypeList; +} +namespace lldb_private { +class UUID; +} +namespace lldb_private { +class VariableList; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class ModuleList ModuleList.h "lldb/Core/ModuleList.h" +/// @brief A collection class for Module objects. +/// +/// Modules in the module collection class are stored as reference +/// counted shared pointers to Module objects. +//---------------------------------------------------------------------- +class ModuleList { +public: + class Notifier { + public: + virtual ~Notifier() = default; + + virtual void ModuleAdded(const ModuleList &module_list, + const lldb::ModuleSP &module_sp) = 0; + virtual void ModuleRemoved(const ModuleList &module_list, + const lldb::ModuleSP &module_sp) = 0; + virtual void ModuleUpdated(const ModuleList &module_list, + const lldb::ModuleSP &old_module_sp, + const lldb::ModuleSP &new_module_sp) = 0; + virtual void WillClearList(const ModuleList &module_list) = 0; + }; + + //------------------------------------------------------------------ + /// Default constructor. + /// + /// Creates an empty list of Module objects. + //------------------------------------------------------------------ + ModuleList(); + + //------------------------------------------------------------------ + /// Copy Constructor. + /// + /// Creates a new module list object with a copy of the modules from + /// \a rhs. + /// + /// @param[in] rhs + /// Another module list object. + //------------------------------------------------------------------ + ModuleList(const ModuleList &rhs); + + ModuleList(ModuleList::Notifier *notifier); + + //------------------------------------------------------------------ + /// Destructor. + //------------------------------------------------------------------ + ~ModuleList(); + + //------------------------------------------------------------------ + /// Assignment operator. + /// + /// Copies the module list from \a rhs into this list. + /// + /// @param[in] rhs + /// Another module list object. + /// + /// @return + /// A const reference to this object. + //------------------------------------------------------------------ + const ModuleList &operator=(const ModuleList &rhs); + + //------------------------------------------------------------------ + /// Append a module to the module list. + /// + /// Appends the module to the collection. + /// + /// @param[in] module_sp + /// A shared pointer to a module to add to this collection. + //------------------------------------------------------------------ + void Append(const lldb::ModuleSP &module_sp); + + //------------------------------------------------------------------ + /// Append a module to the module list and remove any equivalent + /// modules. Equivalent modules are ones whose file, platform file + /// and architecture matches. + /// + /// Replaces the module to the collection. + /// + /// @param[in] module_sp + /// A shared pointer to a module to replace in this collection. + //------------------------------------------------------------------ + void ReplaceEquivalent(const lldb::ModuleSP &module_sp); + + bool AppendIfNeeded(const lldb::ModuleSP &module_sp); + + void Append(const ModuleList &module_list); + + bool AppendIfNeeded(const ModuleList &module_list); + + bool ReplaceModule(const lldb::ModuleSP &old_module_sp, + const lldb::ModuleSP &new_module_sp); + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Clears the list of modules and releases a reference to each + /// module object and if the reference count goes to zero, the + /// module will be deleted. + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + /// Clear the object's state. + /// + /// Clears the list of modules and releases a reference to each + /// module object and if the reference count goes to zero, the + /// module will be deleted. Also release all memory that might be + /// held by any collection classes (like std::vector) + //------------------------------------------------------------------ + void Destroy(); + + //------------------------------------------------------------------ + /// Dump the description of each module contained in this list. + /// + /// Dump the description of each module contained in this list to + /// the supplied stream \a s. + /// + /// @param[in] s + /// The stream to which to dump the object description. + /// + /// @see Module::Dump(Stream *) const + //------------------------------------------------------------------ + void Dump(Stream *s) const; + + void LogUUIDAndPaths(Log *log, const char *prefix_cstr); + + std::recursive_mutex &GetMutex() const { return m_modules_mutex; } + + size_t GetIndexForModule(const Module *module) const; + + //------------------------------------------------------------------ + /// Get the module shared pointer for the module at index \a idx. + /// + /// @param[in] idx + /// An index into this module collection. + /// + /// @return + /// A shared pointer to a Module which can contain NULL if + /// \a idx is out of range. + /// + /// @see ModuleList::GetSize() + //------------------------------------------------------------------ + lldb::ModuleSP GetModuleAtIndex(size_t idx) const; + + //------------------------------------------------------------------ + /// Get the module shared pointer for the module at index \a idx without + /// acquiring the ModuleList mutex. This MUST already have been + /// acquired with ModuleList::GetMutex and locked for this call to be safe. + /// + /// @param[in] idx + /// An index into this module collection. + /// + /// @return + /// A shared pointer to a Module which can contain NULL if + /// \a idx is out of range. + /// + /// @see ModuleList::GetSize() + //------------------------------------------------------------------ + lldb::ModuleSP GetModuleAtIndexUnlocked(size_t idx) const; + + //------------------------------------------------------------------ + /// Get the module pointer for the module at index \a idx. + /// + /// @param[in] idx + /// An index into this module collection. + /// + /// @return + /// A pointer to a Module which can by nullptr if \a idx is out + /// of range. + /// + /// @see ModuleList::GetSize() + //------------------------------------------------------------------ + Module *GetModulePointerAtIndex(size_t idx) const; + + //------------------------------------------------------------------ + /// Get the module pointer for the module at index \a idx without + /// acquiring the ModuleList mutex. This MUST already have been + /// acquired with ModuleList::GetMutex and locked for this call to be safe. + /// + /// @param[in] idx + /// An index into this module collection. + /// + /// @return + /// A pointer to a Module which can by nullptr if \a idx is out + /// of range. + /// + /// @see ModuleList::GetSize() + //------------------------------------------------------------------ + Module *GetModulePointerAtIndexUnlocked(size_t idx) const; + + //------------------------------------------------------------------ + /// Find compile units by partial or full path. + /// + /// Finds all compile units that match \a path in all of the modules + /// and returns the results in \a sc_list. + /// + /// @param[in] path + /// The name of the compile unit we are looking for. + /// + /// @param[in] append + /// If \b true, then append any compile units that were found + /// to \a sc_list. If \b false, then the \a sc_list is cleared + /// and the contents of \a sc_list are replaced. + /// + /// @param[out] sc_list + /// A symbol context list that gets filled in with all of the + /// matches. + /// + /// @return + /// The number of matches added to \a sc_list. + //------------------------------------------------------------------ + size_t FindCompileUnits(const FileSpec &path, bool append, + SymbolContextList &sc_list) const; + + //------------------------------------------------------------------ + /// @see Module::FindFunctions () + //------------------------------------------------------------------ + size_t FindFunctions(const ConstString &name, uint32_t name_type_mask, + bool include_symbols, bool include_inlines, bool append, + SymbolContextList &sc_list) const; + + //------------------------------------------------------------------ + /// @see Module::FindFunctionSymbols () + //------------------------------------------------------------------ + size_t FindFunctionSymbols(const ConstString &name, uint32_t name_type_mask, + SymbolContextList &sc_list); + + //------------------------------------------------------------------ + /// @see Module::FindFunctions () + //------------------------------------------------------------------ + size_t FindFunctions(const RegularExpression &name, bool include_symbols, + bool include_inlines, 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 UINT32_MAX to get all possible matches. + /// + /// @param[in] variable_list + /// A list of variables that gets the matches appended to (if + /// \a append it \b true), or replace (if \a append is \b false). + /// + /// @return + /// The number of matches added to \a variable_list. + //------------------------------------------------------------------ + size_t FindGlobalVariables(const ConstString &name, bool append, + size_t max_matches, + VariableList &variable_list) const; + + //------------------------------------------------------------------ + /// Find global and static variables by regular expression. + /// + /// @param[in] regex + /// A regular expression to use when matching the name. + /// + /// @param[in] append + /// If \b true, any matches will be appended to \a + /// variable_list, else matches replace the contents of + /// \a variable_list. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a + /// max_matches. Specify UINT32_MAX to get all possible matches. + /// + /// @param[in] variable_list + /// A list of variables that gets the matches appended to (if + /// \a append it \b true), or replace (if \a append is \b false). + /// + /// @return + /// The number of matches added to \a variable_list. + //------------------------------------------------------------------ + size_t FindGlobalVariables(const RegularExpression ®ex, bool append, + size_t max_matches, + VariableList &variable_list) const; + + //------------------------------------------------------------------ + /// Finds the first module whose file specification matches \a + /// file_spec. + /// + /// @param[in] file_spec_ptr + /// A file specification object to match against the Module's + /// file specifications. If \a file_spec does not have + /// directory information, matches will occur by matching only + /// the basename of any modules in this list. If this value is + /// NULL, then file specifications won't be compared when + /// searching for matching modules. + /// + /// @param[in] arch_ptr + /// The architecture to search for if non-NULL. If this value + /// is NULL no architecture matching will be performed. + /// + /// @param[in] uuid_ptr + /// The uuid to search for if non-NULL. If this value is NULL + /// no uuid matching will be performed. + /// + /// @param[in] object_name + /// An optional object name that must match as well. This value + /// can be NULL. + /// + /// @param[out] matching_module_list + /// A module list that gets filled in with any modules that + /// match the search criteria. + /// + /// @return + /// The number of matching modules found by the search. + //------------------------------------------------------------------ + size_t FindModules(const ModuleSpec &module_spec, + ModuleList &matching_module_list) const; + + lldb::ModuleSP FindModule(const Module *module_ptr) const; + + //------------------------------------------------------------------ + // Find a module by UUID + // + // The UUID value for a module is extracted from the ObjectFile and + // is the MD5 checksum, or a smarter object file equivalent, so + // finding modules by UUID values is very efficient and accurate. + //------------------------------------------------------------------ + lldb::ModuleSP FindModule(const UUID &uuid) const; + + lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const; + + size_t FindSymbolsWithNameAndType(const ConstString &name, + lldb::SymbolType symbol_type, + SymbolContextList &sc_list, + bool append = false) const; + + size_t FindSymbolsMatchingRegExAndType(const RegularExpression ®ex, + lldb::SymbolType symbol_type, + SymbolContextList &sc_list, + bool append = false) const; + + //------------------------------------------------------------------ + /// Find types by name. + /// + /// @param[in] sc + /// A symbol context that scopes where to extract a type list + /// from. + /// + /// @param[in] name + /// The name of the type we are looking for. + /// + /// @param[in] append + /// If \b true, any matches will be appended to \a + /// variable_list, else matches replace the contents of + /// \a variable_list. + /// + /// @param[in] max_matches + /// Allow the number of matches to be limited to \a + /// max_matches. Specify UINT32_MAX to get all possible matches. + /// + /// @param[in] encoding + /// Limit the search to specific types, or get all types if + /// set to Type::invalid. + /// + /// @param[in] udt_name + /// If the encoding is a user defined type, specify the name + /// of the user defined type ("struct", "union", "class", etc). + /// + /// @param[out] type_list + /// A type list gets populated with any matches. + /// + /// @return + /// The number of matches added to \a type_list. + //------------------------------------------------------------------ + size_t FindTypes(const SymbolContext &sc, const ConstString &name, + bool name_is_fully_qualified, size_t max_matches, + llvm::DenseSet &searched_symbol_files, + TypeList &types) const; + + bool FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const; + + //------------------------------------------------------------------ + /// Find addresses by file/line + /// + /// @param[in] target_sp + /// The target the addresses are desired for. + /// + /// @param[in] file + /// Source file to locate. + /// + /// @param[in] line + /// Source line to locate. + /// + /// @param[in] function + /// Optional filter function. Addresses within this function will be + /// added to the 'local' list. All others will be added to the 'extern' + /// list. + /// + /// @param[out] output_local + /// All matching addresses within 'function' + /// + /// @param[out] output_extern + /// All matching addresses not within 'function' + void FindAddressesForLine(const lldb::TargetSP target_sp, + const FileSpec &file, uint32_t line, + Function *function, + std::vector
&output_local, + std::vector
&output_extern); + + bool Remove(const lldb::ModuleSP &module_sp); + + size_t Remove(ModuleList &module_list); + + bool RemoveIfOrphaned(const Module *module_ptr); + + size_t RemoveOrphans(bool mandatory); + + bool ResolveFileAddress(lldb::addr_t vm_addr, Address &so_addr) const; + + //------------------------------------------------------------------ + /// @copydoc Module::ResolveSymbolContextForAddress (const Address + /// &,uint32_t,SymbolContext&) + //------------------------------------------------------------------ + uint32_t ResolveSymbolContextForAddress(const Address &so_addr, + uint32_t resolve_scope, + SymbolContext &sc) const; + + //------------------------------------------------------------------ + /// @copydoc Module::ResolveSymbolContextForFilePath (const char + /// *,uint32_t,bool,uint32_t,SymbolContextList&) + //------------------------------------------------------------------ + uint32_t ResolveSymbolContextForFilePath(const char *file_path, uint32_t line, + bool check_inlines, + uint32_t resolve_scope, + SymbolContextList &sc_list) const; + + //------------------------------------------------------------------ + /// @copydoc Module::ResolveSymbolContextsForFileSpec (const FileSpec + /// &,uint32_t,bool,uint32_t,SymbolContextList&) + //------------------------------------------------------------------ + uint32_t ResolveSymbolContextsForFileSpec(const FileSpec &file_spec, + uint32_t line, bool check_inlines, + uint32_t resolve_scope, + SymbolContextList &sc_list) const; + + //------------------------------------------------------------------ + /// Gets the size of the module list. + /// + /// @return + /// The number of modules in the module list. + //------------------------------------------------------------------ + size_t GetSize() const; + + bool LoadScriptingResourcesInTarget(Target *target, std::list &errors, + Stream *feedback_stream = nullptr, + bool continue_on_error = true); + + static bool ModuleIsInCache(const Module *module_ptr); + + static Status GetSharedModule(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr, + bool always_create = false); + + static bool RemoveSharedModule(lldb::ModuleSP &module_sp); + + static size_t FindSharedModules(const ModuleSpec &module_spec, + ModuleList &matching_module_list); + + static size_t RemoveOrphanSharedModules(bool mandatory); + + static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr); + + void ForEach(std::function const + &callback) const; + +protected: + //------------------------------------------------------------------ + // Class typedefs. + //------------------------------------------------------------------ + typedef std::vector + collection; ///< The module collection type. + + void AppendImpl(const lldb::ModuleSP &module_sp, bool use_notifier = true); + + bool RemoveImpl(const lldb::ModuleSP &module_sp, bool use_notifier = true); + + collection::iterator RemoveImpl(collection::iterator pos, + bool use_notifier = true); + + void ClearImpl(bool use_notifier = true); + + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + collection m_modules; ///< The collection of modules. + mutable std::recursive_mutex m_modules_mutex; + + Notifier *m_notifier; + +public: + typedef LockingAdaptedIterable + ModuleIterable; + ModuleIterable Modules() { return ModuleIterable(m_modules, GetMutex()); } + + typedef AdaptedIterable + ModuleIterableNoLocking; + ModuleIterableNoLocking ModulesNoLocking() { + return ModuleIterableNoLocking(m_modules); + } +}; + +} // namespace lldb_private + +#endif // liblldb_ModuleList_h_ diff --git a/include/lldb/Core/ModuleSpec.h b/include/lldb/Core/ModuleSpec.h new file mode 100644 index 000000000..ce851d8af --- /dev/null +++ b/include/lldb/Core/ModuleSpec.h @@ -0,0 +1,425 @@ +//===-- ModuleSpec.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ModuleSpec_h_ +#define liblldb_ModuleSpec_h_ + +// Project includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Target/PathMappingList.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/UUID.h" + +// Other libraries and framework includes +#include "llvm/Support/Chrono.h" + +// C Includes +// C++ Includes +#include +#include + +namespace lldb_private { + +class ModuleSpec { +public: + ModuleSpec() + : m_file(), m_platform_file(), m_symbol_file(), m_arch(), m_uuid(), + m_object_name(), m_object_offset(0), m_object_size(0), + m_source_mappings() {} + + ModuleSpec(const FileSpec &file_spec) + : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(), + m_uuid(), m_object_name(), m_object_offset(0), + m_object_size(file_spec.GetByteSize()), m_source_mappings() {} + + ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) + : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(arch), + m_uuid(), m_object_name(), m_object_offset(0), + m_object_size(file_spec.GetByteSize()), m_source_mappings() {} + + ModuleSpec(const ModuleSpec &rhs) + : m_file(rhs.m_file), m_platform_file(rhs.m_platform_file), + m_symbol_file(rhs.m_symbol_file), m_arch(rhs.m_arch), + m_uuid(rhs.m_uuid), m_object_name(rhs.m_object_name), + m_object_offset(rhs.m_object_offset), m_object_size(rhs.m_object_size), + m_object_mod_time(rhs.m_object_mod_time), + m_source_mappings(rhs.m_source_mappings) {} + + ModuleSpec &operator=(const ModuleSpec &rhs) { + if (this != &rhs) { + m_file = rhs.m_file; + m_platform_file = rhs.m_platform_file; + m_symbol_file = rhs.m_symbol_file; + m_arch = rhs.m_arch; + m_uuid = rhs.m_uuid; + m_object_name = rhs.m_object_name; + m_object_offset = rhs.m_object_offset; + m_object_size = rhs.m_object_size; + m_object_mod_time = rhs.m_object_mod_time; + m_source_mappings = rhs.m_source_mappings; + } + return *this; + } + + FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } + + const FileSpec *GetFileSpecPtr() const { + return (m_file ? &m_file : nullptr); + } + + FileSpec &GetFileSpec() { return m_file; } + + const FileSpec &GetFileSpec() const { return m_file; } + + FileSpec *GetPlatformFileSpecPtr() { + return (m_platform_file ? &m_platform_file : nullptr); + } + + const FileSpec *GetPlatformFileSpecPtr() const { + return (m_platform_file ? &m_platform_file : nullptr); + } + + FileSpec &GetPlatformFileSpec() { return m_platform_file; } + + const FileSpec &GetPlatformFileSpec() const { return m_platform_file; } + + FileSpec *GetSymbolFileSpecPtr() { + return (m_symbol_file ? &m_symbol_file : nullptr); + } + + const FileSpec *GetSymbolFileSpecPtr() const { + return (m_symbol_file ? &m_symbol_file : nullptr); + } + + FileSpec &GetSymbolFileSpec() { return m_symbol_file; } + + const FileSpec &GetSymbolFileSpec() const { return m_symbol_file; } + + ArchSpec *GetArchitecturePtr() { + return (m_arch.IsValid() ? &m_arch : nullptr); + } + + const ArchSpec *GetArchitecturePtr() const { + return (m_arch.IsValid() ? &m_arch : nullptr); + } + + ArchSpec &GetArchitecture() { return m_arch; } + + const ArchSpec &GetArchitecture() const { return m_arch; } + + UUID *GetUUIDPtr() { return (m_uuid.IsValid() ? &m_uuid : nullptr); } + + const UUID *GetUUIDPtr() const { + return (m_uuid.IsValid() ? &m_uuid : nullptr); + } + + UUID &GetUUID() { return m_uuid; } + + const UUID &GetUUID() const { return m_uuid; } + + ConstString &GetObjectName() { return m_object_name; } + + const ConstString &GetObjectName() const { return m_object_name; } + + uint64_t GetObjectOffset() const { return m_object_offset; } + + void SetObjectOffset(uint64_t object_offset) { + m_object_offset = object_offset; + } + + uint64_t GetObjectSize() const { return m_object_size; } + + void SetObjectSize(uint64_t object_size) { m_object_size = object_size; } + + llvm::sys::TimePoint<> &GetObjectModificationTime() { + return m_object_mod_time; + } + + const llvm::sys::TimePoint<> &GetObjectModificationTime() const { + return m_object_mod_time; + } + + PathMappingList &GetSourceMappingList() const { return m_source_mappings; } + + void Clear() { + m_file.Clear(); + m_platform_file.Clear(); + m_symbol_file.Clear(); + m_arch.Clear(); + m_uuid.Clear(); + m_object_name.Clear(); + m_object_offset = 0; + m_object_size = 0; + m_source_mappings.Clear(false); + m_object_mod_time = llvm::sys::TimePoint<>(); + } + + explicit operator bool() const { + if (m_file) + return true; + if (m_platform_file) + return true; + if (m_symbol_file) + return true; + if (m_arch.IsValid()) + return true; + if (m_uuid.IsValid()) + return true; + if (m_object_name) + return true; + if (m_object_size) + return true; + if (m_object_mod_time != llvm::sys::TimePoint<>()) + return true; + return false; + } + + void Dump(Stream &strm) const { + bool dumped_something = false; + if (m_file) { + strm.PutCString("file = '"); + strm << m_file; + strm.PutCString("'"); + dumped_something = true; + } + if (m_platform_file) { + if (dumped_something) + strm.PutCString(", "); + strm.PutCString("platform_file = '"); + strm << m_platform_file; + strm.PutCString("'"); + dumped_something = true; + } + if (m_symbol_file) { + if (dumped_something) + strm.PutCString(", "); + strm.PutCString("symbol_file = '"); + strm << m_symbol_file; + strm.PutCString("'"); + dumped_something = true; + } + if (m_arch.IsValid()) { + if (dumped_something) + strm.PutCString(", "); + strm.Printf("arch = "); + m_arch.DumpTriple(strm); + dumped_something = true; + } + if (m_uuid.IsValid()) { + if (dumped_something) + strm.PutCString(", "); + strm.PutCString("uuid = "); + m_uuid.Dump(&strm); + dumped_something = true; + } + if (m_object_name) { + if (dumped_something) + strm.PutCString(", "); + strm.Printf("object_name = %s", m_object_name.GetCString()); + dumped_something = true; + } + if (m_object_offset > 0) { + if (dumped_something) + strm.PutCString(", "); + strm.Printf("object_offset = %" PRIu64, m_object_offset); + dumped_something = true; + } + if (m_object_size > 0) { + if (dumped_something) + strm.PutCString(", "); + strm.Printf("object size = %" PRIu64, m_object_size); + dumped_something = true; + } + if (m_object_mod_time != llvm::sys::TimePoint<>()) { + if (dumped_something) + strm.PutCString(", "); + strm.Format("object_mod_time = {0:x+}", + uint64_t(llvm::sys::toTimeT(m_object_mod_time))); + } + } + + bool Matches(const ModuleSpec &match_module_spec, + bool exact_arch_match) const { + if (match_module_spec.GetUUIDPtr() && + match_module_spec.GetUUID() != GetUUID()) + return false; + if (match_module_spec.GetObjectName() && + match_module_spec.GetObjectName() != GetObjectName()) + return false; + if (match_module_spec.GetFileSpecPtr()) { + const FileSpec &fspec = match_module_spec.GetFileSpec(); + if (!FileSpec::Equal(fspec, GetFileSpec(), + fspec.GetDirectory().IsEmpty() == false)) + return false; + } + if (GetPlatformFileSpec() && match_module_spec.GetPlatformFileSpecPtr()) { + const FileSpec &fspec = match_module_spec.GetPlatformFileSpec(); + if (!FileSpec::Equal(fspec, GetPlatformFileSpec(), + fspec.GetDirectory().IsEmpty() == false)) + return false; + } + // Only match the symbol file spec if there is one in this ModuleSpec + if (GetSymbolFileSpec() && match_module_spec.GetSymbolFileSpecPtr()) { + const FileSpec &fspec = match_module_spec.GetSymbolFileSpec(); + if (!FileSpec::Equal(fspec, GetSymbolFileSpec(), + fspec.GetDirectory().IsEmpty() == false)) + return false; + } + if (match_module_spec.GetArchitecturePtr()) { + if (exact_arch_match) { + if (!GetArchitecture().IsExactMatch( + match_module_spec.GetArchitecture())) + return false; + } else { + if (!GetArchitecture().IsCompatibleMatch( + match_module_spec.GetArchitecture())) + return false; + } + } + return true; + } + +protected: + FileSpec m_file; + FileSpec m_platform_file; + FileSpec m_symbol_file; + ArchSpec m_arch; + UUID m_uuid; + ConstString m_object_name; + uint64_t m_object_offset; + uint64_t m_object_size; + llvm::sys::TimePoint<> m_object_mod_time; + mutable PathMappingList m_source_mappings; +}; + +class ModuleSpecList { +public: + ModuleSpecList() : m_specs(), m_mutex() {} + + ModuleSpecList(const ModuleSpecList &rhs) : m_specs(), m_mutex() { + std::lock_guard lhs_guard(m_mutex); + std::lock_guard rhs_guard(rhs.m_mutex); + m_specs = rhs.m_specs; + } + + ~ModuleSpecList() = default; + + ModuleSpecList &operator=(const ModuleSpecList &rhs) { + if (this != &rhs) { + std::lock_guard lhs_guard(m_mutex); + std::lock_guard rhs_guard(rhs.m_mutex); + m_specs = rhs.m_specs; + } + return *this; + } + + size_t GetSize() const { + std::lock_guard guard(m_mutex); + return m_specs.size(); + } + + void Clear() { + std::lock_guard guard(m_mutex); + m_specs.clear(); + } + + void Append(const ModuleSpec &spec) { + std::lock_guard guard(m_mutex); + m_specs.push_back(spec); + } + + void Append(const ModuleSpecList &rhs) { + std::lock_guard lhs_guard(m_mutex); + std::lock_guard rhs_guard(rhs.m_mutex); + m_specs.insert(m_specs.end(), rhs.m_specs.begin(), rhs.m_specs.end()); + } + + // The index "i" must be valid and this can't be used in + // multi-threaded code as no mutex lock is taken. + ModuleSpec &GetModuleSpecRefAtIndex(size_t i) { return m_specs[i]; } + + bool GetModuleSpecAtIndex(size_t i, ModuleSpec &module_spec) const { + std::lock_guard guard(m_mutex); + if (i < m_specs.size()) { + module_spec = m_specs[i]; + return true; + } + module_spec.Clear(); + return false; + } + + bool FindMatchingModuleSpec(const ModuleSpec &module_spec, + ModuleSpec &match_module_spec) const { + std::lock_guard guard(m_mutex); + bool exact_arch_match = true; + for (auto spec : m_specs) { + if (spec.Matches(module_spec, exact_arch_match)) { + match_module_spec = spec; + return true; + } + } + + // If there was an architecture, retry with a compatible arch + if (module_spec.GetArchitecturePtr()) { + exact_arch_match = false; + for (auto spec : m_specs) { + if (spec.Matches(module_spec, exact_arch_match)) { + match_module_spec = spec; + return true; + } + } + } + match_module_spec.Clear(); + return false; + } + + size_t FindMatchingModuleSpecs(const ModuleSpec &module_spec, + ModuleSpecList &matching_list) const { + std::lock_guard guard(m_mutex); + bool exact_arch_match = true; + const size_t initial_match_count = matching_list.GetSize(); + for (auto spec : m_specs) { + if (spec.Matches(module_spec, exact_arch_match)) + matching_list.Append(spec); + } + + // If there was an architecture, retry with a compatible arch if no matches + // were found + if (module_spec.GetArchitecturePtr() && + (initial_match_count == matching_list.GetSize())) { + exact_arch_match = false; + for (auto spec : m_specs) { + if (spec.Matches(module_spec, exact_arch_match)) + matching_list.Append(spec); + } + } + return matching_list.GetSize() - initial_match_count; + } + + void Dump(Stream &strm) { + std::lock_guard guard(m_mutex); + uint32_t idx = 0; + for (auto spec : m_specs) { + strm.Printf("[%u] ", idx); + spec.Dump(strm); + strm.EOL(); + ++idx; + } + } + +protected: + typedef std::vector collection; ///< The module collection type. + collection m_specs; ///< The collection of modules. + mutable std::recursive_mutex m_mutex; +}; + +} // namespace lldb_private + +#endif // liblldb_ModuleSpec_h_ diff --git a/include/lldb/Core/Opcode.h b/include/lldb/Core/Opcode.h new file mode 100644 index 000000000..33857457b --- /dev/null +++ b/include/lldb/Core/Opcode.h @@ -0,0 +1,279 @@ +//===-- Opcode.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_Opcode_h +#define lldb_Opcode_h + +#include "lldb/Utility/Endian.h" +#include "lldb/lldb-enumerations.h" // for ByteOrder, ByteOrder::eByteOrde... + +#include "llvm/Support/MathExtras.h" + +#include // for assert +#include // for uint32_t, uint8_t, uint16_t +#include + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Stream; +} + +namespace lldb { +class SBInstruction; +} + +namespace lldb_private { + +class Opcode { +public: + enum Type { + eTypeInvalid, + eType8, + eType16, + eType16_2, // a 32-bit Thumb instruction, made up of two words + eType32, + eType64, + eTypeBytes + }; + + Opcode() : m_byte_order(lldb::eByteOrderInvalid), m_type(eTypeInvalid) {} + + Opcode(uint8_t inst, lldb::ByteOrder order) + : m_byte_order(order), m_type(eType8) { + m_data.inst8 = inst; + } + + Opcode(uint16_t inst, lldb::ByteOrder order) + : m_byte_order(order), m_type(eType16) { + m_data.inst16 = inst; + } + + Opcode(uint32_t inst, lldb::ByteOrder order) + : m_byte_order(order), m_type(eType32) { + m_data.inst32 = inst; + } + + Opcode(uint64_t inst, lldb::ByteOrder order) + : m_byte_order(order), m_type(eType64) { + m_data.inst64 = inst; + } + + Opcode(uint8_t *bytes, size_t length) + : m_byte_order(lldb::eByteOrderInvalid) { + SetOpcodeBytes(bytes, length); + } + + void Clear() { + m_byte_order = lldb::eByteOrderInvalid; + m_type = Opcode::eTypeInvalid; + } + + Opcode::Type GetType() const { return m_type; } + + uint8_t GetOpcode8(uint8_t invalid_opcode = UINT8_MAX) const { + switch (m_type) { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + return m_data.inst8; + case Opcode::eType16: + break; + case Opcode::eType16_2: + break; + case Opcode::eType32: + break; + case Opcode::eType64: + break; + case Opcode::eTypeBytes: + break; + } + return invalid_opcode; + } + + uint16_t GetOpcode16(uint16_t invalid_opcode = UINT16_MAX) const { + switch (m_type) { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + return m_data.inst8; + case Opcode::eType16: + return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16; + case Opcode::eType16_2: + break; + case Opcode::eType32: + break; + case Opcode::eType64: + break; + case Opcode::eTypeBytes: + break; + } + return invalid_opcode; + } + + uint32_t GetOpcode32(uint32_t invalid_opcode = UINT32_MAX) const { + switch (m_type) { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + return m_data.inst8; + case Opcode::eType16: + return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16; + case Opcode::eType16_2: // passthrough + case Opcode::eType32: + return GetEndianSwap() ? llvm::ByteSwap_32(m_data.inst32) : m_data.inst32; + case Opcode::eType64: + break; + case Opcode::eTypeBytes: + break; + } + return invalid_opcode; + } + + uint64_t GetOpcode64(uint64_t invalid_opcode = UINT64_MAX) const { + switch (m_type) { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + return m_data.inst8; + case Opcode::eType16: + return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16; + case Opcode::eType16_2: // passthrough + case Opcode::eType32: + return GetEndianSwap() ? llvm::ByteSwap_32(m_data.inst32) : m_data.inst32; + case Opcode::eType64: + return GetEndianSwap() ? llvm::ByteSwap_64(m_data.inst64) : m_data.inst64; + case Opcode::eTypeBytes: + break; + } + return invalid_opcode; + } + + void SetOpcode8(uint8_t inst, lldb::ByteOrder order) { + m_type = eType8; + m_data.inst8 = inst; + m_byte_order = order; + } + + void SetOpcode16(uint16_t inst, lldb::ByteOrder order) { + m_type = eType16; + m_data.inst16 = inst; + m_byte_order = order; + } + + void SetOpcode16_2(uint32_t inst, lldb::ByteOrder order) { + m_type = eType16_2; + m_data.inst32 = inst; + m_byte_order = order; + } + + void SetOpcode32(uint32_t inst, lldb::ByteOrder order) { + m_type = eType32; + m_data.inst32 = inst; + m_byte_order = order; + } + + void SetOpcode64(uint64_t inst, lldb::ByteOrder order) { + m_type = eType64; + m_data.inst64 = inst; + m_byte_order = order; + } + + void SetOpcodeBytes(const void *bytes, size_t length) { + if (bytes != nullptr && length > 0) { + m_type = eTypeBytes; + m_data.inst.length = length; + assert(length < sizeof(m_data.inst.bytes)); + memcpy(m_data.inst.bytes, bytes, length); + m_byte_order = lldb::eByteOrderInvalid; + } else { + m_type = eTypeInvalid; + m_data.inst.length = 0; + } + } + + int Dump(Stream *s, uint32_t min_byte_width); + + const void *GetOpcodeBytes() const { + return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr); + } + + uint32_t GetByteSize() const { + switch (m_type) { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + return sizeof(m_data.inst8); + case Opcode::eType16: + return sizeof(m_data.inst16); + case Opcode::eType16_2: // passthrough + case Opcode::eType32: + return sizeof(m_data.inst32); + case Opcode::eType64: + return sizeof(m_data.inst64); + case Opcode::eTypeBytes: + return m_data.inst.length; + } + return 0; + } + + // Get the opcode exactly as it would be laid out in memory. + uint32_t GetData(DataExtractor &data) const; + +protected: + friend class lldb::SBInstruction; + + const void *GetOpcodeDataBytes() const { + switch (m_type) { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + return &m_data.inst8; + case Opcode::eType16: + return &m_data.inst16; + case Opcode::eType16_2: // passthrough + case Opcode::eType32: + return &m_data.inst32; + case Opcode::eType64: + return &m_data.inst64; + case Opcode::eTypeBytes: + return m_data.inst.bytes; + } + return nullptr; + } + + lldb::ByteOrder GetDataByteOrder() const; + + bool GetEndianSwap() const { + return (m_byte_order == lldb::eByteOrderBig && + endian::InlHostByteOrder() == lldb::eByteOrderLittle) || + (m_byte_order == lldb::eByteOrderLittle && + endian::InlHostByteOrder() == lldb::eByteOrderBig); + } + + lldb::ByteOrder m_byte_order; + + Opcode::Type m_type; + union { + uint8_t inst8; + uint16_t inst16; + uint32_t inst32; + uint64_t inst64; + struct { + uint8_t bytes[16]; // This must be big enough to handle any opcode for any + // supported target. + uint8_t length; + } inst; + } m_data; +}; + +} // namespace lldb_private + +#endif // lldb_Opcode_h diff --git a/include/lldb/Core/PluginInterface.h b/include/lldb/Core/PluginInterface.h new file mode 100644 index 000000000..edda15a1a --- /dev/null +++ b/include/lldb/Core/PluginInterface.h @@ -0,0 +1,32 @@ +//===-- PluginInterface.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_PluginInterface_h_ +#define liblldb_PluginInterface_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class PluginInterface { +public: + virtual ~PluginInterface() {} + + virtual ConstString GetPluginName() = 0; + + virtual uint32_t GetPluginVersion() = 0; +}; + +} // namespace lldb_private + +#endif // liblldb_PluginInterface_h_ diff --git a/include/lldb/Core/PluginManager.h b/include/lldb/Core/PluginManager.h new file mode 100644 index 000000000..d9851e5ec --- /dev/null +++ b/include/lldb/Core/PluginManager.h @@ -0,0 +1,531 @@ +//===-- 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/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" // for Status +#include "lldb/lldb-enumerations.h" // for ScriptLanguage +#include "lldb/lldb-forward.h" // for OptionValuePropertiesSP +#include "lldb/lldb-private-interfaces.h" // for DebuggerInitializeCallback +#include "llvm/ADT/StringRef.h" // for StringRef + +#include // for size_t +#include // for uint32_t + +namespace lldb_private { +class CommandInterpreter; +} +namespace lldb_private { +class ConstString; +} +namespace lldb_private { +class Debugger; +} +namespace lldb_private { +class StringList; +} +namespace lldb_private { + +class PluginManager { +public: + static void Initialize(); + + static void Terminate(); + + //------------------------------------------------------------------ + // ABI + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + ABICreateInstance create_callback); + + static bool UnregisterPlugin(ABICreateInstance create_callback); + + static ABICreateInstance GetABICreateCallbackAtIndex(uint32_t idx); + + static ABICreateInstance + GetABICreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // Disassembler + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + DisassemblerCreateInstance create_callback); + + static bool UnregisterPlugin(DisassemblerCreateInstance create_callback); + + static DisassemblerCreateInstance + GetDisassemblerCreateCallbackAtIndex(uint32_t idx); + + static DisassemblerCreateInstance + GetDisassemblerCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // DynamicLoader + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + DynamicLoaderCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr); + + static bool UnregisterPlugin(DynamicLoaderCreateInstance create_callback); + + static DynamicLoaderCreateInstance + GetDynamicLoaderCreateCallbackAtIndex(uint32_t idx); + + static DynamicLoaderCreateInstance + GetDynamicLoaderCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // JITLoader + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + JITLoaderCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr); + + static bool UnregisterPlugin(JITLoaderCreateInstance create_callback); + + static JITLoaderCreateInstance + GetJITLoaderCreateCallbackAtIndex(uint32_t idx); + + static JITLoaderCreateInstance + GetJITLoaderCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // EmulateInstruction + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + EmulateInstructionCreateInstance create_callback); + + static bool + UnregisterPlugin(EmulateInstructionCreateInstance create_callback); + + static EmulateInstructionCreateInstance + GetEmulateInstructionCreateCallbackAtIndex(uint32_t idx); + + static EmulateInstructionCreateInstance + GetEmulateInstructionCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // OperatingSystem + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + OperatingSystemCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback); + + static bool UnregisterPlugin(OperatingSystemCreateInstance create_callback); + + static OperatingSystemCreateInstance + GetOperatingSystemCreateCallbackAtIndex(uint32_t idx); + + static OperatingSystemCreateInstance + GetOperatingSystemCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // Language + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + LanguageCreateInstance create_callback); + + static bool UnregisterPlugin(LanguageCreateInstance create_callback); + + static LanguageCreateInstance GetLanguageCreateCallbackAtIndex(uint32_t idx); + + static LanguageCreateInstance + GetLanguageCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // LanguageRuntime + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + LanguageRuntimeCreateInstance create_callback, + LanguageRuntimeGetCommandObject command_callback = nullptr); + + static bool UnregisterPlugin(LanguageRuntimeCreateInstance create_callback); + + static LanguageRuntimeCreateInstance + GetLanguageRuntimeCreateCallbackAtIndex(uint32_t idx); + + static LanguageRuntimeGetCommandObject + GetLanguageRuntimeGetCommandObjectAtIndex(uint32_t idx); + + static LanguageRuntimeCreateInstance + GetLanguageRuntimeCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // SystemRuntime + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + SystemRuntimeCreateInstance create_callback); + + static bool UnregisterPlugin(SystemRuntimeCreateInstance create_callback); + + static SystemRuntimeCreateInstance + GetSystemRuntimeCreateCallbackAtIndex(uint32_t idx); + + static SystemRuntimeCreateInstance + GetSystemRuntimeCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // ObjectFile + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + ObjectFileCreateInstance create_callback, + ObjectFileCreateMemoryInstance create_memory_callback, + ObjectFileGetModuleSpecifications get_module_specifications, + ObjectFileSaveCore save_core = nullptr); + + static bool UnregisterPlugin(ObjectFileCreateInstance create_callback); + + static ObjectFileCreateInstance + GetObjectFileCreateCallbackAtIndex(uint32_t idx); + + static ObjectFileCreateMemoryInstance + GetObjectFileCreateMemoryCallbackAtIndex(uint32_t idx); + + static ObjectFileGetModuleSpecifications + GetObjectFileGetModuleSpecificationsCallbackAtIndex(uint32_t idx); + + static ObjectFileCreateInstance + GetObjectFileCreateCallbackForPluginName(const ConstString &name); + + static ObjectFileCreateMemoryInstance + GetObjectFileCreateMemoryCallbackForPluginName(const ConstString &name); + + static Status SaveCore(const lldb::ProcessSP &process_sp, + const FileSpec &outfile); + + //------------------------------------------------------------------ + // ObjectContainer + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + ObjectContainerCreateInstance create_callback, + ObjectFileGetModuleSpecifications get_module_specifications); + + static bool UnregisterPlugin(ObjectContainerCreateInstance create_callback); + + static ObjectContainerCreateInstance + GetObjectContainerCreateCallbackAtIndex(uint32_t idx); + + static ObjectContainerCreateInstance + GetObjectContainerCreateCallbackForPluginName(const ConstString &name); + + static ObjectFileGetModuleSpecifications + GetObjectContainerGetModuleSpecificationsCallbackAtIndex(uint32_t idx); + + //------------------------------------------------------------------ + // Platform + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + PlatformCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr); + + static bool UnregisterPlugin(PlatformCreateInstance create_callback); + + static PlatformCreateInstance GetPlatformCreateCallbackAtIndex(uint32_t idx); + + static PlatformCreateInstance + GetPlatformCreateCallbackForPluginName(const ConstString &name); + + static const char *GetPlatformPluginNameAtIndex(uint32_t idx); + + static const char *GetPlatformPluginDescriptionAtIndex(uint32_t idx); + + static size_t AutoCompletePlatformName(llvm::StringRef partial_name, + StringList &matches); + //------------------------------------------------------------------ + // Process + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + ProcessCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr); + + static bool UnregisterPlugin(ProcessCreateInstance create_callback); + + static ProcessCreateInstance GetProcessCreateCallbackAtIndex(uint32_t idx); + + static ProcessCreateInstance + GetProcessCreateCallbackForPluginName(const ConstString &name); + + static const char *GetProcessPluginNameAtIndex(uint32_t idx); + + static const char *GetProcessPluginDescriptionAtIndex(uint32_t idx); + + //------------------------------------------------------------------ + // ScriptInterpreter + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + lldb::ScriptLanguage script_lang, + ScriptInterpreterCreateInstance create_callback); + + static bool UnregisterPlugin(ScriptInterpreterCreateInstance create_callback); + + static ScriptInterpreterCreateInstance + GetScriptInterpreterCreateCallbackAtIndex(uint32_t idx); + + static lldb::ScriptInterpreterSP + GetScriptInterpreterForLanguage(lldb::ScriptLanguage script_lang, + CommandInterpreter &interpreter); + + //------------------------------------------------------------------ + // StructuredDataPlugin + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Register a StructuredDataPlugin class along with optional + /// callbacks for debugger initialization and Process launch info + /// filtering and manipulation. + /// + /// @param[in] name + /// The name of the plugin. + /// + /// @param[in] description + /// A description string for the plugin. + /// + /// @param[in] create_callback + /// The callback that will be invoked to create an instance of + /// the callback. This may not be nullptr. + /// + /// @param[in] debugger_init_callback + /// An optional callback that will be made when a Debugger + /// instance is initialized. + /// + /// @param[in] filter_callback + /// An optional callback that will be invoked before LLDB + /// launches a process for debugging. The callback must + /// do the following: + /// 1. Only do something if the plugin's behavior is enabled. + /// 2. Only make changes for processes that are relevant to the + /// plugin. The callback gets a pointer to the Target, which + /// can be inspected as needed. The ProcessLaunchInfo is + /// provided in read-write mode, and may be modified by the + /// plugin if, for instance, additional environment variables + /// are needed to support the feature when enabled. + /// + /// @return + /// Returns true upon success; otherwise, false. + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + StructuredDataPluginCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr, + StructuredDataFilterLaunchInfo filter_callback = nullptr); + + static bool + UnregisterPlugin(StructuredDataPluginCreateInstance create_callback); + + static StructuredDataPluginCreateInstance + GetStructuredDataPluginCreateCallbackAtIndex(uint32_t idx); + + static StructuredDataPluginCreateInstance + GetStructuredDataPluginCreateCallbackForPluginName(const ConstString &name); + + static StructuredDataFilterLaunchInfo + GetStructuredDataFilterCallbackAtIndex(uint32_t idx, + bool &iteration_complete); + + //------------------------------------------------------------------ + // SymbolFile + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + SymbolFileCreateInstance create_callback, + DebuggerInitializeCallback debugger_init_callback = nullptr); + + static bool UnregisterPlugin(SymbolFileCreateInstance create_callback); + + static SymbolFileCreateInstance + GetSymbolFileCreateCallbackAtIndex(uint32_t idx); + + static SymbolFileCreateInstance + GetSymbolFileCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // SymbolVendor + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + SymbolVendorCreateInstance create_callback); + + static bool UnregisterPlugin(SymbolVendorCreateInstance create_callback); + + static SymbolVendorCreateInstance + GetSymbolVendorCreateCallbackAtIndex(uint32_t idx); + + static SymbolVendorCreateInstance + GetSymbolVendorCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // UnwindAssembly + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + UnwindAssemblyCreateInstance create_callback); + + static bool UnregisterPlugin(UnwindAssemblyCreateInstance create_callback); + + static UnwindAssemblyCreateInstance + GetUnwindAssemblyCreateCallbackAtIndex(uint32_t idx); + + static UnwindAssemblyCreateInstance + GetUnwindAssemblyCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // MemoryHistory + //------------------------------------------------------------------ + static bool RegisterPlugin(const ConstString &name, const char *description, + MemoryHistoryCreateInstance create_callback); + + static bool UnregisterPlugin(MemoryHistoryCreateInstance create_callback); + + static MemoryHistoryCreateInstance + GetMemoryHistoryCreateCallbackAtIndex(uint32_t idx); + + static MemoryHistoryCreateInstance + GetMemoryHistoryCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // InstrumentationRuntime + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + InstrumentationRuntimeCreateInstance create_callback, + InstrumentationRuntimeGetType get_type_callback); + + static bool + UnregisterPlugin(InstrumentationRuntimeCreateInstance create_callback); + + static InstrumentationRuntimeGetType + GetInstrumentationRuntimeGetTypeCallbackAtIndex(uint32_t idx); + + static InstrumentationRuntimeCreateInstance + GetInstrumentationRuntimeCreateCallbackAtIndex(uint32_t idx); + + static InstrumentationRuntimeCreateInstance + GetInstrumentationRuntimeCreateCallbackForPluginName(const ConstString &name); + + //------------------------------------------------------------------ + // TypeSystem + //------------------------------------------------------------------ + static bool RegisterPlugin( + const ConstString &name, const char *description, + TypeSystemCreateInstance create_callback, + TypeSystemEnumerateSupportedLanguages enumerate_languages_callback); + + static bool UnregisterPlugin(TypeSystemCreateInstance create_callback); + + static TypeSystemCreateInstance + GetTypeSystemCreateCallbackAtIndex(uint32_t idx); + + static TypeSystemCreateInstance + GetTypeSystemCreateCallbackForPluginName(const ConstString &name); + + static TypeSystemEnumerateSupportedLanguages + GetTypeSystemEnumerateSupportedLanguagesCallbackAtIndex(uint32_t idx); + + static TypeSystemEnumerateSupportedLanguages + GetTypeSystemEnumerateSupportedLanguagesCallbackForPluginName( + const ConstString &name); + + //------------------------------------------------------------------ + // REPL + //------------------------------------------------------------------ + static bool + RegisterPlugin(const ConstString &name, const char *description, + REPLCreateInstance create_callback, + REPLEnumerateSupportedLanguages enumerate_languages_callback); + + static bool UnregisterPlugin(REPLCreateInstance create_callback); + + static REPLCreateInstance GetREPLCreateCallbackAtIndex(uint32_t idx); + + static REPLCreateInstance + GetREPLCreateCallbackForPluginName(const ConstString &name); + + static REPLEnumerateSupportedLanguages + GetREPLEnumerateSupportedLanguagesCallbackAtIndex(uint32_t idx); + + static REPLEnumerateSupportedLanguages + GetREPLSystemEnumerateSupportedLanguagesCallbackForPluginName( + const ConstString &name); + + //------------------------------------------------------------------ + // Some plug-ins might register a DebuggerInitializeCallback + // callback when registering the plug-in. After a new Debugger + // instance is created, this DebuggerInitialize function will get + // called. This allows plug-ins to install Properties and do any + // other initialization that requires a debugger instance. + //------------------------------------------------------------------ + static void DebuggerInitialize(Debugger &debugger); + + static lldb::OptionValuePropertiesSP + GetSettingForDynamicLoaderPlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForDynamicLoaderPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForPlatformPlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForPlatformPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForProcessPlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForProcessPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForSymbolFilePlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForSymbolFilePlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForJITLoaderPlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForJITLoaderPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForOperatingSystemPlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForOperatingSystemPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); + + static lldb::OptionValuePropertiesSP + GetSettingForStructuredDataPlugin(Debugger &debugger, + const ConstString &setting_name); + + static bool CreateSettingForStructuredDataPlugin( + Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, + const ConstString &description, bool is_global_property); +}; + +} // namespace lldb_private + +#endif // liblldb_PluginManager_h_ diff --git a/include/lldb/Core/RangeMap.h b/include/lldb/Core/RangeMap.h new file mode 100644 index 000000000..e37dcd7df --- /dev/null +++ b/include/lldb/Core/RangeMap.h @@ -0,0 +1,1224 @@ +//===-- RangeMap.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RangeMap_h_ +#define liblldb_RangeMap_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "llvm/ADT/SmallVector.h" + +// Project includes +#include "lldb/lldb-private.h" + +// Uncomment to make sure all Range objects are sorted when needed +//#define ASSERT_RANGEMAP_ARE_SORTED + +namespace lldb_private { + +//---------------------------------------------------------------------- +// Templatized classes for dealing with generic ranges and also +// collections of ranges, or collections of ranges that have associated +// data. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// A simple range class where you get to define the type of the range +// base "B", and the type used for the range byte size "S". +//---------------------------------------------------------------------- +template struct Range { + typedef B BaseType; + typedef S SizeType; + + BaseType base; + SizeType size; + + Range() : base(0), size(0) {} + + Range(BaseType b, SizeType s) : base(b), size(s) {} + + void Clear(BaseType b = 0) { + base = b; + size = 0; + } + + // Set the start value for the range, and keep the same size + BaseType GetRangeBase() const { return base; } + + void SetRangeBase(BaseType b) { base = b; } + + void Slide(BaseType slide) { base += slide; } + + bool Union(const Range &rhs) + { + if (DoesAdjoinOrIntersect(rhs)) + { + auto new_end = std::max(GetRangeEnd(), rhs.GetRangeEnd()); + base = std::min(base, rhs.base); + size = new_end - base; + return true; + } + return false; + } + + BaseType GetRangeEnd() const { return base + size; } + + void SetRangeEnd(BaseType end) { + if (end > base) + size = end - base; + else + size = 0; + } + + SizeType GetByteSize() const { return size; } + + void SetByteSize(SizeType s) { size = s; } + + bool IsValid() const { return size > 0; } + + bool Contains(BaseType r) const { + return (GetRangeBase() <= r) && (r < GetRangeEnd()); + } + + bool ContainsEndInclusive(BaseType r) const { + return (GetRangeBase() <= r) && (r <= GetRangeEnd()); + } + + bool Contains(const Range &range) const { + return Contains(range.GetRangeBase()) && + ContainsEndInclusive(range.GetRangeEnd()); + } + + // Returns true if the two ranges adjoing or intersect + bool DoesAdjoinOrIntersect(const Range &rhs) const { + const BaseType lhs_base = this->GetRangeBase(); + const BaseType rhs_base = rhs.GetRangeBase(); + const BaseType lhs_end = this->GetRangeEnd(); + const BaseType rhs_end = rhs.GetRangeEnd(); + bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base); + return result; + } + + // Returns true if the two ranges intersect + bool DoesIntersect(const Range &rhs) const { + const BaseType lhs_base = this->GetRangeBase(); + const BaseType rhs_base = rhs.GetRangeBase(); + const BaseType lhs_end = this->GetRangeEnd(); + const BaseType rhs_end = rhs.GetRangeEnd(); + bool result = (lhs_base < rhs_end) && (lhs_end > rhs_base); + return result; + } + + bool operator<(const Range &rhs) const { + if (base == rhs.base) + return size < rhs.size; + return base < rhs.base; + } + + bool operator==(const Range &rhs) const { + return base == rhs.base && size == rhs.size; + } + + bool operator!=(const Range &rhs) const { + return base != rhs.base || size != rhs.size; + } +}; + +//---------------------------------------------------------------------- +// A range array class where you get to define the type of the ranges +// that the collection contains. +//---------------------------------------------------------------------- + +template class RangeArray { +public: + typedef B BaseType; + typedef S SizeType; + typedef Range Entry; + typedef llvm::SmallVector Collection; + + RangeArray() = default; + + ~RangeArray() = default; + + void Append(const Entry &entry) { m_entries.push_back(entry); } + + void Append(B base, S size) { m_entries.emplace_back(base, size); } + + bool RemoveEntrtAtIndex(uint32_t idx) { + if (idx < m_entries.size()) { + m_entries.erase(m_entries.begin() + idx); + return true; + } + return false; + } + + void Sort() { + if (m_entries.size() > 1) + std::stable_sort(m_entries.begin(), m_entries.end()); + } + +#ifdef ASSERT_RANGEMAP_ARE_SORTED + bool IsSorted() const { + typename Collection::const_iterator pos, end, prev; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && *pos < *prev) + return false; + } + return true; + } +#endif + + void CombineConsecutiveRanges() { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + // Can't combine if ranges if we have zero or one range + if (m_entries.size() > 1) { + // The list should be sorted prior to calling this function + typename Collection::iterator pos; + typename Collection::iterator end; + typename Collection::iterator prev; + bool can_combine = false; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; + pos != end; prev = pos++) { + if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) { + can_combine = true; + break; + } + } + + // We we can combine at least one entry, then we make a new collection + // and populate it accordingly, and then swap it into place. + if (can_combine) { + Collection minimal_ranges; + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; + pos != end; prev = pos++) { + if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) + minimal_ranges.back().SetRangeEnd( + std::max(prev->GetRangeEnd(), pos->GetRangeEnd())); + else + minimal_ranges.push_back(*pos); + } + // Use the swap technique in case our new vector is much smaller. + // We must swap when using the STL because std::vector objects never + // release or reduce the memory once it has been allocated/reserved. + m_entries.swap(minimal_ranges); + } + } + } + + BaseType GetMinRangeBase(BaseType fail_value) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (m_entries.empty()) + return fail_value; + // m_entries must be sorted, so if we aren't empty, we grab the + // first range's base + return m_entries.front().GetRangeBase(); + } + + BaseType GetMaxRangeEnd(BaseType fail_value) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (m_entries.empty()) + return fail_value; + // m_entries must be sorted, so if we aren't empty, we grab the + // last range's end + return m_entries.back().GetRangeEnd(); + } + + void Slide(BaseType slide) { + typename Collection::iterator pos, end; + for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos) + pos->Slide(slide); + } + + void Clear() { m_entries.clear(); } + + bool IsEmpty() const { return m_entries.empty(); } + + size_t GetSize() const { return m_entries.size(); } + + const Entry *GetEntryAtIndex(size_t i) const { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + + // Clients must ensure that "i" is a valid index prior to calling this + // function + const Entry &GetEntryRef(size_t i) const { return m_entries[i]; } + + Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); } + + const Entry *Back() const { + return (m_entries.empty() ? nullptr : &m_entries.back()); + } + + static bool BaseLessThan(const Entry &lhs, const Entry &rhs) { + return lhs.GetRangeBase() < rhs.GetRangeBase(); + } + + uint32_t FindEntryIndexThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry(addr, 1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return std::distance(begin, pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) + return std::distance(begin, pos); + } + } + return UINT32_MAX; + } + + const Entry *FindEntryThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry(addr, 1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) { + return &(*pos); + } + } + } + return nullptr; + } + + const Entry *FindEntryThatContains(const Entry &range) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, range, BaseLessThan); + + if (pos != end && pos->Contains(range)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(range)) { + return &(*pos); + } + } + } + return nullptr; + } + +protected: + Collection m_entries; +}; + +template class RangeVector { +public: + typedef B BaseType; + typedef S SizeType; + typedef Range Entry; + typedef std::vector Collection; + + RangeVector() = default; + + ~RangeVector() = default; + + void Append(const Entry &entry) { m_entries.push_back(entry); } + + void Append(B base, S size) { m_entries.emplace_back(base, size); } + + // Insert an item into a sorted list and optionally combine it with any + // adjacent blocks if requested. + void Insert(const Entry &entry, bool combine) { + if (m_entries.empty()) { + m_entries.push_back(entry); + return; + } + auto begin = m_entries.begin(); + auto end = m_entries.end(); + auto pos = std::lower_bound(begin, end, entry); + if (combine) { + if (pos != end && pos->Union(entry)) { + CombinePrevAndNext(pos); + return; + } + if (pos != begin) { + auto prev = pos - 1; + if (prev->Union(entry)) { + CombinePrevAndNext(prev); + return; + } + } + } + m_entries.insert(pos, entry); + } + + bool RemoveEntryAtIndex(uint32_t idx) { + if (idx < m_entries.size()) { + m_entries.erase(m_entries.begin() + idx); + return true; + } + return false; + } + + void Sort() { + if (m_entries.size() > 1) + std::stable_sort(m_entries.begin(), m_entries.end()); + } + +#ifdef ASSERT_RANGEMAP_ARE_SORTED + bool IsSorted() const { + typename Collection::const_iterator pos, end, prev; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && *pos < *prev) + return false; + } + return true; + } +#endif + + void CombineConsecutiveRanges() { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + // Can't combine if ranges if we have zero or one range + if (m_entries.size() > 1) { + // The list should be sorted prior to calling this function + typename Collection::iterator pos; + typename Collection::iterator end; + typename Collection::iterator prev; + bool can_combine = false; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; + pos != end; prev = pos++) { + if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) { + can_combine = true; + break; + } + } + + // We we can combine at least one entry, then we make a new collection + // and populate it accordingly, and then swap it into place. + if (can_combine) { + Collection minimal_ranges; + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; + pos != end; prev = pos++) { + if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) + minimal_ranges.back().SetRangeEnd( + std::max(prev->GetRangeEnd(), pos->GetRangeEnd())); + else + minimal_ranges.push_back(*pos); + } + // Use the swap technique in case our new vector is much smaller. + // We must swap when using the STL because std::vector objects never + // release or reduce the memory once it has been allocated/reserved. + m_entries.swap(minimal_ranges); + } + } + } + + BaseType GetMinRangeBase(BaseType fail_value) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (m_entries.empty()) + return fail_value; + // m_entries must be sorted, so if we aren't empty, we grab the + // first range's base + return m_entries.front().GetRangeBase(); + } + + BaseType GetMaxRangeEnd(BaseType fail_value) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (m_entries.empty()) + return fail_value; + // m_entries must be sorted, so if we aren't empty, we grab the + // last range's end + return m_entries.back().GetRangeEnd(); + } + + void Slide(BaseType slide) { + typename Collection::iterator pos, end; + for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos) + pos->Slide(slide); + } + + void Clear() { m_entries.clear(); } + + void Reserve(typename Collection::size_type size) { m_entries.reserve(size); } + + bool IsEmpty() const { return m_entries.empty(); } + + size_t GetSize() const { return m_entries.size(); } + + const Entry *GetEntryAtIndex(size_t i) const { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + + // Clients must ensure that "i" is a valid index prior to calling this + // function + Entry &GetEntryRef(size_t i) { return m_entries[i]; } + const Entry &GetEntryRef(size_t i) const { return m_entries[i]; } + + Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); } + + const Entry *Back() const { + return (m_entries.empty() ? nullptr : &m_entries.back()); + } + + static bool BaseLessThan(const Entry &lhs, const Entry &rhs) { + return lhs.GetRangeBase() < rhs.GetRangeBase(); + } + + uint32_t FindEntryIndexThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry(addr, 1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return std::distance(begin, pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) + return std::distance(begin, pos); + } + } + return UINT32_MAX; + } + + const Entry *FindEntryThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry(addr, 1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) { + return &(*pos); + } + } + } + return nullptr; + } + + const Entry *FindEntryThatContains(const Entry &range) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, range, BaseLessThan); + + if (pos != end && pos->Contains(range)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(range)) { + return &(*pos); + } + } + } + return nullptr; + } + +protected: + + void CombinePrevAndNext(typename Collection::iterator pos) { + // Check if the prev or next entries in case they need to be unioned with + // the entry pointed to by "pos". + if (pos != m_entries.begin()) { + auto prev = pos - 1; + if (prev->Union(*pos)) + m_entries.erase(pos); + pos = prev; + } + + auto end = m_entries.end(); + if (pos != end) { + auto next = pos + 1; + if (next != end) { + if (pos->Union(*next)) + m_entries.erase(next); + } + } + return; + } + + Collection m_entries; +}; + +//---------------------------------------------------------------------- +// A simple range with data class where you get to define the type of +// the range base "B", the type used for the range byte size "S", and +// the type for the associated data "T". +//---------------------------------------------------------------------- +template +struct RangeData : public Range { + typedef T DataType; + + DataType data; + + RangeData() : Range(), data() {} + + RangeData(B base, S size) : Range(base, size), data() {} + + RangeData(B base, S size, DataType d) : Range(base, size), data(d) {} + + bool operator<(const RangeData &rhs) const { + if (this->base == rhs.base) { + if (this->size == rhs.size) + return this->data < rhs.data; + else + return this->size < rhs.size; + } + return this->base < rhs.base; + } + + bool operator==(const RangeData &rhs) const { + return this->GetRangeBase() == rhs.GetRangeBase() && + this->GetByteSize() == rhs.GetByteSize() && this->data == rhs.data; + } + + bool operator!=(const RangeData &rhs) const { + return this->GetRangeBase() != rhs.GetRangeBase() || + this->GetByteSize() != rhs.GetByteSize() || this->data != rhs.data; + } +}; + +template class RangeDataArray { +public: + typedef RangeData Entry; + typedef llvm::SmallVector Collection; + + RangeDataArray() = default; + + ~RangeDataArray() = default; + + void Append(const Entry &entry) { m_entries.push_back(entry); } + + void Sort() { + if (m_entries.size() > 1) + std::stable_sort(m_entries.begin(), m_entries.end()); + } + +#ifdef ASSERT_RANGEMAP_ARE_SORTED + bool IsSorted() const { + typename Collection::const_iterator pos, end, prev; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && *pos < *prev) + return false; + } + return true; + } +#endif + + void CombineConsecutiveEntriesWithEqualData() { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + typename Collection::iterator pos; + typename Collection::iterator end; + typename Collection::iterator prev; + bool can_combine = false; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && prev->data == pos->data) { + can_combine = true; + break; + } + } + + // We we can combine at least one entry, then we make a new collection + // and populate it accordingly, and then swap it into place. + if (can_combine) { + Collection minimal_ranges; + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; + pos != end; prev = pos++) { + if (prev != end && prev->data == pos->data) + minimal_ranges.back().SetRangeEnd(pos->GetRangeEnd()); + else + minimal_ranges.push_back(*pos); + } + // Use the swap technique in case our new vector is much smaller. + // We must swap when using the STL because std::vector objects never + // release or reduce the memory once it has been allocated/reserved. + m_entries.swap(minimal_ranges); + } + } + + void Clear() { m_entries.clear(); } + + bool IsEmpty() const { return m_entries.empty(); } + + size_t GetSize() const { return m_entries.size(); } + + const Entry *GetEntryAtIndex(size_t i) const { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + + // Clients must ensure that "i" is a valid index prior to calling this + // function + const Entry &GetEntryRef(size_t i) const { return m_entries[i]; } + + static bool BaseLessThan(const Entry &lhs, const Entry &rhs) { + return lhs.GetRangeBase() < rhs.GetRangeBase(); + } + + uint32_t FindEntryIndexThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry(addr, 1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return std::distance(begin, pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) + return std::distance(begin, pos); + } + } + return UINT32_MAX; + } + + Entry *FindEntryThatContains(B addr) { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry; + entry.SetRangeBase(addr); + entry.SetByteSize(1); + typename Collection::iterator begin = m_entries.begin(); + typename Collection::iterator end = m_entries.end(); + typename Collection::iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) { + return &(*pos); + } + } + } + return nullptr; + } + + const Entry *FindEntryThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry; + entry.SetRangeBase(addr); + entry.SetByteSize(1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + if (pos != end && pos->Contains(addr)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(addr)) { + return &(*pos); + } + } + } + return nullptr; + } + + const Entry *FindEntryThatContains(const Entry &range) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, range, BaseLessThan); + + if (pos != end && pos->Contains(range)) { + return &(*pos); + } else if (pos != begin) { + --pos; + if (pos->Contains(range)) { + return &(*pos); + } + } + } + return nullptr; + } + + Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); } + + const Entry *Back() const { + return (m_entries.empty() ? nullptr : &m_entries.back()); + } + +protected: + Collection m_entries; +}; + +// Same as RangeDataArray, but uses std::vector as to not +// require static storage of N items in the class itself +template class RangeDataVector { +public: + typedef RangeData Entry; + typedef std::vector Collection; + + RangeDataVector() = default; + + ~RangeDataVector() = default; + + void Append(const Entry &entry) { m_entries.push_back(entry); } + + void Sort() { + if (m_entries.size() > 1) + std::stable_sort(m_entries.begin(), m_entries.end()); + } + +#ifdef ASSERT_RANGEMAP_ARE_SORTED + bool IsSorted() const { + typename Collection::const_iterator pos, end, prev; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && *pos < *prev) + return false; + } + return true; + } +#endif + + void CombineConsecutiveEntriesWithEqualData() { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + typename Collection::iterator pos; + typename Collection::iterator end; + typename Collection::iterator prev; + bool can_combine = false; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && prev->data == pos->data) { + can_combine = true; + break; + } + } + + // We we can combine at least one entry, then we make a new collection + // and populate it accordingly, and then swap it into place. + if (can_combine) { + Collection minimal_ranges; + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; + pos != end; prev = pos++) { + if (prev != end && prev->data == pos->data) + minimal_ranges.back().SetRangeEnd(pos->GetRangeEnd()); + else + minimal_ranges.push_back(*pos); + } + // Use the swap technique in case our new vector is much smaller. + // We must swap when using the STL because std::vector objects never + // release or reduce the memory once it has been allocated/reserved. + m_entries.swap(minimal_ranges); + } + } + + // Calculate the byte size of ranges with zero byte sizes by finding + // the next entry with a base address > the current base address + void CalculateSizesOfZeroByteSizeRanges(S full_size = 0) { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + typename Collection::iterator pos; + typename Collection::iterator end; + typename Collection::iterator next; + for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos) { + if (pos->GetByteSize() == 0) { + // Watch out for multiple entries with same address and make sure + // we find an entry that is greater than the current base address + // before we use that for the size + auto curr_base = pos->GetRangeBase(); + for (next = pos + 1; next != end; ++next) { + auto next_base = next->GetRangeBase(); + if (next_base > curr_base) { + pos->SetByteSize(next_base - curr_base); + break; + } + } + if (next == end && full_size > curr_base) + pos->SetByteSize(full_size - curr_base); + } + } + } + + void Clear() { m_entries.clear(); } + + void Reserve(typename Collection::size_type size) { m_entries.resize(size); } + + bool IsEmpty() const { return m_entries.empty(); } + + size_t GetSize() const { return m_entries.size(); } + + const Entry *GetEntryAtIndex(size_t i) const { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + + Entry *GetMutableEntryAtIndex(size_t i) { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + + // Clients must ensure that "i" is a valid index prior to calling this + // function + const Entry &GetEntryRef(size_t i) const { return m_entries[i]; } + + static bool BaseLessThan(const Entry &lhs, const Entry &rhs) { + return lhs.GetRangeBase() < rhs.GetRangeBase(); + } + + uint32_t FindEntryIndexThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry(addr, 1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + while (pos != begin && pos[-1].Contains(addr)) + --pos; + + if (pos != end && pos->Contains(addr)) + return std::distance(begin, pos); + } + return UINT32_MAX; + } + + uint32_t FindEntryIndexesThatContain(B addr, + std::vector &indexes) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + + if (!m_entries.empty()) { + typename Collection::const_iterator pos; + for (const auto &entry : m_entries) { + if (entry.Contains(addr)) + indexes.push_back(entry.data); + } + } + return indexes.size(); + } + + Entry *FindEntryThatContains(B addr) { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry; + entry.SetRangeBase(addr); + entry.SetByteSize(1); + typename Collection::iterator begin = m_entries.begin(); + typename Collection::iterator end = m_entries.end(); + typename Collection::iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + while (pos != begin && pos[-1].Contains(addr)) + --pos; + + if (pos != end && pos->Contains(addr)) + return &(*pos); + } + return nullptr; + } + + const Entry *FindEntryThatContains(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry; + entry.SetRangeBase(addr); + entry.SetByteSize(1); + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + while (pos != begin && pos[-1].Contains(addr)) + --pos; + + if (pos != end && pos->Contains(addr)) + return &(*pos); + } + return nullptr; + } + + const Entry *FindEntryThatContains(const Entry &range) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(begin, end, range, BaseLessThan); + + while (pos != begin && pos[-1].Contains(range)) + --pos; + + if (pos != end && pos->Contains(range)) + return &(*pos); + } + return nullptr; + } + + const Entry *FindEntryStartsAt(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + auto begin = m_entries.begin(), end = m_entries.end(); + auto pos = std::lower_bound(begin, end, Entry(addr, 1), BaseLessThan); + if (pos != end && pos->base == addr) + return &(*pos); + } + return nullptr; + } + + // This method will return the entry that contains the given address, or the + // entry following that address. If you give it an address of 0 and the first + // entry starts at address 0x100, you will get the entry at 0x100. + // + // For most uses, FindEntryThatContains is the correct one to use, this is a + // less commonly needed behavior. It was added for core file memory regions, + // where we want to present a gap in the memory regions as a distinct region, + // so we need to know the start address of the next memory section that + // exists. + const Entry *FindEntryThatContainsOrFollows(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + typename Collection::const_iterator begin = m_entries.begin(); + typename Collection::const_iterator end = m_entries.end(); + typename Collection::const_iterator pos = + std::lower_bound(m_entries.begin(), end, addr, + [](const Entry &lhs, B rhs_base) -> bool { + return lhs.GetRangeEnd() <= rhs_base; + }); + + while (pos != begin && pos[-1].Contains(addr)) + --pos; + + if (pos != end) + return &(*pos); + } + return nullptr; + } + + Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); } + + const Entry *Back() const { + return (m_entries.empty() ? nullptr : &m_entries.back()); + } + +protected: + Collection m_entries; +}; + +//---------------------------------------------------------------------- +// A simple range with data class where you get to define the type of +// the range base "B", the type used for the range byte size "S", and +// the type for the associated data "T". +//---------------------------------------------------------------------- +template struct AddressData { + typedef B BaseType; + typedef T DataType; + + BaseType addr; + DataType data; + + AddressData() : addr(), data() {} + + AddressData(B a, DataType d) : addr(a), data(d) {} + + bool operator<(const AddressData &rhs) const { + if (this->addr == rhs.addr) + return this->data < rhs.data; + return this->addr < rhs.addr; + } + + bool operator==(const AddressData &rhs) const { + return this->addr == rhs.addr && this->data == rhs.data; + } + + bool operator!=(const AddressData &rhs) const { + return this->addr != rhs.addr || this->data == rhs.data; + } +}; + +template class AddressDataArray { +public: + typedef AddressData Entry; + typedef llvm::SmallVector Collection; + + AddressDataArray() = default; + + ~AddressDataArray() = default; + + void Append(const Entry &entry) { m_entries.push_back(entry); } + + void Sort() { + if (m_entries.size() > 1) + std::stable_sort(m_entries.begin(), m_entries.end()); + } + +#ifdef ASSERT_RANGEMAP_ARE_SORTED + bool IsSorted() const { + typename Collection::const_iterator pos, end, prev; + // First we determine if we can combine any of the Entry objects so we + // don't end up allocating and making a new collection for no reason + for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; + prev = pos++) { + if (prev != end && *pos < *prev) + return false; + } + return true; + } +#endif + + void Clear() { m_entries.clear(); } + + bool IsEmpty() const { return m_entries.empty(); } + + size_t GetSize() const { return m_entries.size(); } + + const Entry *GetEntryAtIndex(size_t i) const { + return ((i < m_entries.size()) ? &m_entries[i] : nullptr); + } + + // Clients must ensure that "i" is a valid index prior to calling this + // function + const Entry &GetEntryRef(size_t i) const { return m_entries[i]; } + + static bool BaseLessThan(const Entry &lhs, const Entry &rhs) { + return lhs.addr < rhs.addr; + } + + Entry *FindEntry(B addr, bool exact_match_only) { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + if (!m_entries.empty()) { + Entry entry; + entry.addr = addr; + typename Collection::iterator begin = m_entries.begin(); + typename Collection::iterator end = m_entries.end(); + typename Collection::iterator pos = + std::lower_bound(begin, end, entry, BaseLessThan); + + while (pos != begin && pos[-1].addr == addr) + --pos; + + if (pos != end) { + if (pos->addr == addr || !exact_match_only) + return &(*pos); + } + } + return nullptr; + } + + const Entry *FindNextEntry(const Entry *entry) { + if (entry >= &*m_entries.begin() && entry + 1 < &*m_entries.end()) + return entry + 1; + return nullptr; + } + + Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); } + + const Entry *Back() const { + return (m_entries.empty() ? nullptr : &m_entries.back()); + } + +protected: + Collection m_entries; +}; + +} // namespace lldb_private + +#endif // liblldb_RangeMap_h_ diff --git a/include/lldb/Core/RegisterValue.h b/include/lldb/Core/RegisterValue.h new file mode 100644 index 000000000..a45db00fb --- /dev/null +++ b/include/lldb/Core/RegisterValue.h @@ -0,0 +1,286 @@ +//===-- RegisterValue.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterValue_h +#define lldb_RegisterValue_h + +#include "lldb/Core/Scalar.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Status.h" // for Status +#include "lldb/lldb-enumerations.h" // for ByteOrder, Format +#include "lldb/lldb-types.h" // for offset_t + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/StringRef.h" // for StringRef + +#include // for uint32_t, uint8_t, uint64_t, uin... +#include + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +struct RegisterInfo; +} +namespace lldb_private { + +class RegisterValue { +public: + enum { kMaxRegisterByteSize = 32u }; + + enum Type { + eTypeInvalid, + eTypeUInt8, + eTypeUInt16, + eTypeUInt32, + eTypeUInt64, + eTypeUInt128, + eTypeFloat, + eTypeDouble, + eTypeLongDouble, + eTypeBytes + }; + + RegisterValue() : m_type(eTypeInvalid), m_scalar((unsigned long)0) {} + + explicit RegisterValue(uint8_t inst) : m_type(eTypeUInt8) { m_scalar = inst; } + + explicit RegisterValue(uint16_t inst) : m_type(eTypeUInt16) { + m_scalar = inst; + } + + explicit RegisterValue(uint32_t inst) : m_type(eTypeUInt32) { + m_scalar = inst; + } + + explicit RegisterValue(uint64_t inst) : m_type(eTypeUInt64) { + m_scalar = inst; + } + + explicit RegisterValue(llvm::APInt inst) : m_type(eTypeUInt128) { + m_scalar = llvm::APInt(inst); + } + + explicit RegisterValue(float value) : m_type(eTypeFloat) { m_scalar = value; } + + explicit RegisterValue(double value) : m_type(eTypeDouble) { + m_scalar = value; + } + + explicit RegisterValue(long double value) : m_type(eTypeLongDouble) { + m_scalar = value; + } + + explicit RegisterValue(uint8_t *bytes, size_t length, + lldb::ByteOrder byte_order) { + SetBytes(bytes, length, byte_order); + } + + RegisterValue::Type GetType() const { return m_type; } + + bool CopyValue(const RegisterValue &rhs); + + void SetType(RegisterValue::Type type) { m_type = type; } + + RegisterValue::Type SetType(const RegisterInfo *reg_info); + + bool GetData(DataExtractor &data) const; + + // Copy the register value from this object into a buffer in "dst" + // and obey the "dst_byte_order" when copying the data. Also watch out + // in case "dst_len" is longer or shorter than the register value + // described by "reg_info" and only copy the least significant bytes + // of the register value, or pad the destination with zeroes if the + // register byte size is shorter that "dst_len" (all while correctly + // abiding the "dst_byte_order"). Returns the number of bytes copied + // into "dst". + uint32_t GetAsMemoryData(const RegisterInfo *reg_info, void *dst, + uint32_t dst_len, lldb::ByteOrder dst_byte_order, + Status &error) const; + + uint32_t SetFromMemoryData(const RegisterInfo *reg_info, const void *src, + uint32_t src_len, lldb::ByteOrder src_byte_order, + Status &error); + + bool GetScalarValue(Scalar &scalar) const; + + uint8_t GetAsUInt8(uint8_t fail_value = UINT8_MAX, + bool *success_ptr = nullptr) const { + if (m_type == eTypeUInt8) { + if (success_ptr) + *success_ptr = true; + return m_scalar.UChar(fail_value); + } + if (success_ptr) + *success_ptr = true; + return fail_value; + } + + uint16_t GetAsUInt16(uint16_t fail_value = UINT16_MAX, + bool *success_ptr = nullptr) const; + + uint32_t GetAsUInt32(uint32_t fail_value = UINT32_MAX, + bool *success_ptr = nullptr) const; + + uint64_t GetAsUInt64(uint64_t fail_value = UINT64_MAX, + bool *success_ptr = nullptr) const; + + llvm::APInt GetAsUInt128(const llvm::APInt &fail_value, + bool *success_ptr = nullptr) const; + + float GetAsFloat(float fail_value = 0.0f, bool *success_ptr = nullptr) const; + + double GetAsDouble(double fail_value = 0.0, + bool *success_ptr = nullptr) const; + + long double GetAsLongDouble(long double fail_value = 0.0, + bool *success_ptr = nullptr) const; + + void SetValueToInvalid() { m_type = eTypeInvalid; } + + bool ClearBit(uint32_t bit); + + bool SetBit(uint32_t bit); + + bool operator==(const RegisterValue &rhs) const; + + bool operator!=(const RegisterValue &rhs) const; + + void operator=(uint8_t uint) { + m_type = eTypeUInt8; + m_scalar = uint; + } + + void operator=(uint16_t uint) { + m_type = eTypeUInt16; + m_scalar = uint; + } + + void operator=(uint32_t uint) { + m_type = eTypeUInt32; + m_scalar = uint; + } + + void operator=(uint64_t uint) { + m_type = eTypeUInt64; + m_scalar = uint; + } + + void operator=(llvm::APInt uint) { + m_type = eTypeUInt128; + m_scalar = llvm::APInt(uint); + } + + void operator=(float f) { + m_type = eTypeFloat; + m_scalar = f; + } + + void operator=(double f) { + m_type = eTypeDouble; + m_scalar = f; + } + + void operator=(long double f) { + m_type = eTypeLongDouble; + m_scalar = f; + } + + void SetUInt8(uint8_t uint) { + m_type = eTypeUInt8; + m_scalar = uint; + } + + void SetUInt16(uint16_t uint) { + m_type = eTypeUInt16; + m_scalar = uint; + } + + void SetUInt32(uint32_t uint, Type t = eTypeUInt32) { + m_type = t; + m_scalar = uint; + } + + void SetUInt64(uint64_t uint, Type t = eTypeUInt64) { + m_type = t; + m_scalar = uint; + } + + void SetUInt128(llvm::APInt uint) { + m_type = eTypeUInt128; + m_scalar = uint; + } + + bool SetUInt(uint64_t uint, uint32_t byte_size); + + void SetFloat(float f) { + m_type = eTypeFloat; + m_scalar = f; + } + + void SetDouble(double f) { + m_type = eTypeDouble; + m_scalar = f; + } + + void SetLongDouble(long double f) { + m_type = eTypeLongDouble; + m_scalar = f; + } + + void SetBytes(const void *bytes, size_t length, lldb::ByteOrder byte_order); + + bool SignExtend(uint32_t sign_bitpos); + + Status SetValueFromString(const RegisterInfo *reg_info, + llvm::StringRef value_str); + Status SetValueFromString(const RegisterInfo *reg_info, + const char *value_str) = delete; + + Status SetValueFromData(const RegisterInfo *reg_info, DataExtractor &data, + lldb::offset_t offset, bool partial_data_ok); + + // The default value of 0 for reg_name_right_align_at means no alignment at + // all. + bool Dump(Stream *s, const RegisterInfo *reg_info, bool prefix_with_name, + bool prefix_with_alt_name, lldb::Format format, + uint32_t reg_name_right_align_at = 0) const; + + const void *GetBytes() const; + + lldb::ByteOrder GetByteOrder() const { + if (m_type == eTypeBytes) + return buffer.byte_order; + return endian::InlHostByteOrder(); + } + + uint32_t GetByteSize() const; + + static uint32_t GetMaxByteSize() { return kMaxRegisterByteSize; } + + void Clear(); + +protected: + RegisterValue::Type m_type; + Scalar m_scalar; + + struct { + uint8_t bytes[kMaxRegisterByteSize]; // This must be big enough to hold any + // register for any supported target. + uint8_t length; + lldb::ByteOrder byte_order; + } buffer; +}; + +} // namespace lldb_private + +#endif // lldb_RegisterValue_h diff --git a/include/lldb/Core/STLUtils.h b/include/lldb/Core/STLUtils.h new file mode 100644 index 000000000..d851ed546 --- /dev/null +++ b/include/lldb/Core/STLUtils.h @@ -0,0 +1,85 @@ +//===-- 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_ + +// C Includes +#include + +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes + +//---------------------------------------------------------------------- +// 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 whose value +// is equal to something +//---------------------------------------------------------------------- +template class ValueEquals { +public: + ValueEquals(const S &val) : second_value(val) {} + + // Compare the second item + bool operator()(std::pair elem) { + return elem.second == second_value; + } + +private: + S second_value; +}; + +template +inline void PrintAllCollectionElements(std::ostream &s, const T &coll, + const char *header_cstr = nullptr, + 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 void operator()(T *ptr) { delete ptr; } +}; + +typedef std::vector STLStringArray; +typedef std::vector CStringArray; + +#endif // liblldb_STLUtils_h_ diff --git a/include/lldb/Core/Scalar.h b/include/lldb/Core/Scalar.h new file mode 100644 index 000000000..943398b88 --- /dev/null +++ b/include/lldb/Core/Scalar.h @@ -0,0 +1,380 @@ +//===-- 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/Utility/Status.h" // for Status +#include "lldb/lldb-enumerations.h" // for Encoding, ByteOrder +#include "lldb/lldb-private-types.h" // for type128 + +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" + +#include // for size_t +#include // for uint32_t, uint64_t, int64_t + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Stream; +} + +#define NUM_OF_WORDS_INT128 2 +#define BITWIDTH_INT128 128 +#define NUM_OF_WORDS_INT256 4 +#define BITWIDTH_INT256 256 + +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, + e_uint128, + e_sint128, + e_uint256, + e_sint256 + }; + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + Scalar(); + Scalar(int v) : m_type(e_sint), m_float((float)0) { + m_integer = llvm::APInt(sizeof(int) * 8, v, true); + } + Scalar(unsigned int v) : m_type(e_uint), m_float((float)0) { + m_integer = llvm::APInt(sizeof(int) * 8, v); + } + Scalar(long v) : m_type(e_slong), m_float((float)0) { + m_integer = llvm::APInt(sizeof(long) * 8, v, true); + } + Scalar(unsigned long v) : m_type(e_ulong), m_float((float)0) { + m_integer = llvm::APInt(sizeof(long) * 8, v); + } + Scalar(long long v) : m_type(e_slonglong), m_float((float)0) { + m_integer = llvm::APInt(sizeof(long long) * 8, v, true); + } + Scalar(unsigned long long v) : m_type(e_ulonglong), m_float((float)0) { + m_integer = llvm::APInt(sizeof(long long) * 8, v); + } + Scalar(float v) : m_type(e_float), m_float(v) { m_float = llvm::APFloat(v); } + Scalar(double v) : m_type(e_double), m_float(v) { + m_float = llvm::APFloat(v); + } + Scalar(long double v, bool ieee_quad) + : m_type(e_long_double), m_float((float)0), m_ieee_quad(ieee_quad) { + if (ieee_quad) + m_float = llvm::APFloat(llvm::APFloat::IEEEquad(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + ((type128 *)&v)->x)); + else + m_float = llvm::APFloat(llvm::APFloat::x87DoubleExtended(), + llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + ((type128 *)&v)->x)); + } + Scalar(llvm::APInt v) : m_type(), m_float((float)0) { + m_integer = llvm::APInt(v); + switch (m_integer.getBitWidth()) { + case 8: + case 16: + case 32: + if (m_integer.isSignedIntN(sizeof(sint_t) * 8)) + m_type = e_sint; + else + m_type = e_uint; + break; + case 64: + if (m_integer.isSignedIntN(sizeof(slonglong_t) * 8)) + m_type = e_slonglong; + else + m_type = e_ulonglong; + break; + case 128: + if (m_integer.isSignedIntN(BITWIDTH_INT128)) + m_type = e_sint128; + else + m_type = e_uint128; + break; + case 256: + if (m_integer.isSignedIntN(BITWIDTH_INT256)) + m_type = e_sint256; + else + m_type = e_uint256; + break; + } + } + Scalar(const Scalar &rhs); + // Scalar(const RegisterValue& reg_value); + virtual ~Scalar(); + + bool SignExtend(uint32_t bit_pos); + + bool ExtractBitfield(uint32_t bit_size, uint32_t bit_offset); + + bool SetBit(uint32_t bit); + + bool ClearBit(uint32_t bit); + + const void *GetBytes() const; + + size_t GetByteSize() const; + + bool GetData(DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const; + + size_t GetAsMemoryData(void *dst, size_t dst_len, + lldb::ByteOrder dst_byte_order, Status &error) const; + + bool IsZero() const; + + void Clear() { + m_type = e_void; + m_integer.clearAllBits(); + } + + const char *GetTypeAsCString() const; + + void GetValue(Stream *s, bool show_type) const; + + bool IsValid() const { + return (m_type >= e_sint) && (m_type <= e_long_double); + } + + bool Promote(Scalar::Type type); + + bool Cast(Scalar::Type type); + + bool MakeSigned(); + + bool MakeUnsigned(); + + 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=(llvm::APInt 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; + + unsigned char UChar(unsigned char fail_value = 0) const; + + signed char SChar(char fail_value = 0) const; + + unsigned short UShort(unsigned short fail_value = 0) const; + + short SShort(short fail_value = 0) 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; + + llvm::APInt SInt128(llvm::APInt &fail_value) const; + + llvm::APInt UInt128(const llvm::APInt &fail_value) const; + + llvm::APInt SInt256(llvm::APInt &fail_value) const; + + llvm::APInt UInt256(const llvm::APInt &fail_value) 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; + + Status SetValueFromCString(const char *s, lldb::Encoding encoding, + size_t byte_size); + + Status SetValueFromData(DataExtractor &data, lldb::Encoding encoding, + size_t byte_size); + + static bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) { + if (total_byte_size > 8) + return false; + + if (total_byte_size == 8) + return true; + + const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; + return uval64 <= max; + } + + static bool SIntValueIsValidForSize(int64_t sval64, size_t total_byte_size) { + if (total_byte_size > 8) + return false; + + if (total_byte_size == 8) + return true; + + const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; + const int64_t min = ~(max); + return min <= sval64 && sval64 <= max; + } + +protected: + typedef char schar_t; + typedef unsigned char uchar_t; + typedef short sshort_t; + typedef unsigned short ushort_t; + typedef int sint_t; + typedef unsigned int uint_t; + typedef long slong_t; + typedef unsigned long ulong_t; + typedef long long slonglong_t; + typedef unsigned long long ulonglong_t; + typedef float float_t; + typedef double double_t; + typedef long double long_double_t; + + //------------------------------------------------------------------ + // Classes that inherit from Scalar can see and modify these + //------------------------------------------------------------------ + Scalar::Type m_type; + llvm::APInt m_integer; + llvm::APFloat m_float; + bool m_ieee_quad = false; + +private: + friend const Scalar operator+(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator-(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator/(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator*(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator&(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator|(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator%(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator^(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); + friend bool operator==(const Scalar &lhs, const Scalar &rhs); + friend bool operator!=(const Scalar &lhs, const Scalar &rhs); + friend bool operator<(const Scalar &lhs, const Scalar &rhs); + friend bool operator<=(const Scalar &lhs, const Scalar &rhs); + friend bool operator>(const Scalar &lhs, const Scalar &rhs); + friend bool operator>=(const Scalar &lhs, const Scalar &rhs); +}; + +//---------------------------------------------------------------------- +// Split out the operators into a format where the compiler will be able +// to implicitly convert numbers into Scalar objects. +// +// This allows code like: +// Scalar two(2); +// Scalar four = two * 2; +// Scalar eight = 2 * four; // This would cause an error if the +// // operator* was implemented as a +// // member function. +// SEE: +// Item 19 of "Effective C++ Second Edition" by Scott Meyers +// Differentiate among members functions, non-member functions, and +// friend functions +//---------------------------------------------------------------------- +const Scalar operator+(const Scalar &lhs, const Scalar &rhs); +const Scalar operator-(const Scalar &lhs, const Scalar &rhs); +const Scalar operator/(const Scalar &lhs, const Scalar &rhs); +const Scalar operator*(const Scalar &lhs, const Scalar &rhs); +const Scalar operator&(const Scalar &lhs, const Scalar &rhs); +const Scalar operator|(const Scalar &lhs, const Scalar &rhs); +const Scalar operator%(const Scalar &lhs, const Scalar &rhs); +const Scalar operator^(const Scalar &lhs, const Scalar &rhs); +const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); +const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); +bool operator==(const Scalar &lhs, const Scalar &rhs); +bool operator!=(const Scalar &lhs, const Scalar &rhs); +bool operator<(const Scalar &lhs, const Scalar &rhs); +bool operator<=(const Scalar &lhs, const Scalar &rhs); +bool operator>(const Scalar &lhs, const Scalar &rhs); +bool operator>=(const Scalar &lhs, const Scalar &rhs); + +} // namespace lldb_private + +#endif // liblldb_Scalar_h_ diff --git a/include/lldb/Core/SearchFilter.h b/include/lldb/Core/SearchFilter.h new file mode 100644 index 000000000..5861afc80 --- /dev/null +++ b/include/lldb/Core/SearchFilter.h @@ -0,0 +1,531 @@ +//===-- 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_ + +#include "lldb/Core/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" + +#include "lldb/Utility/FileSpec.h" // for FileSpec +#include "lldb/lldb-forward.h" // for SearchFilterSP, TargetSP, Modu... + +#include // for uint32_t + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class Breakpoint; +} +namespace lldb_private { +class CompileUnit; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class Function; +} +namespace lldb_private { +class ModuleList; +} +namespace lldb_private { +class SearchFilter; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContext; +} +namespace lldb_private { +class Target; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Searcher SearchFilter.h "lldb/Core/SearchFilter.h" +/// @brief Class that is driven by the SearchFilter to search the +/// SymbolContext space of the target program. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +/// General Outline: +/// Provides the callback and search depth for the SearchFilter search. +//---------------------------------------------------------------------- + +class Searcher { +public: + typedef enum { + eCallbackReturnStop = 0, // Stop the iteration + eCallbackReturnContinue, // Continue the iteration + eCallbackReturnPop // Pop one level up and continue iterating + } CallbackReturn; + + typedef enum { + eDepthTarget, + eDepthModule, + eDepthCompUnit, + eDepthFunction, + eDepthBlock, + eDepthAddress + } Depth; + + Searcher(); + + virtual ~Searcher(); + + virtual CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool complete) = 0; + + virtual Depth GetDepth() = 0; + + //------------------------------------------------------------------ + /// Prints a canonical description for the searcher to the stream \a s. + /// + /// @param[in] s + /// Stream to which the output is copied. + //------------------------------------------------------------------ + virtual void GetDescription(Stream *s); +}; + +//---------------------------------------------------------------------- +/// @class SearchFilter SearchFilter.h "lldb/Core/SearchFilter.h" +/// @brief Class descends through the SymbolContext space of the target, +/// applying a filter at each stage till it reaches the depth specified by +/// the GetDepth method of the searcher, and calls its callback at that point. +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +/// General Outline: +/// Provides the callback and search depth for the SearchFilter search. +/// +/// The search is done by cooperation between the search filter and the +/// searcher. +/// The search filter does the heavy work of recursing through the SymbolContext +/// space of the target program's symbol space. The Searcher specifies the +/// depth +/// at which it wants its callback to be invoked. Note that since the +/// resolution +/// of the Searcher may be greater than that of the SearchFilter, before the +/// Searcher qualifies an address it should pass it to "AddressPasses." +/// The default implementation is "Everything Passes." +//---------------------------------------------------------------------- + +class SearchFilter { +public: + //------------------------------------------------------------------ + /// The basic constructor takes a Target, which gives the space to search. + /// + /// @param[in] target + /// The Target that provides the module list to search. + //------------------------------------------------------------------ + SearchFilter(const lldb::TargetSP &target_sp); + + SearchFilter(const SearchFilter &rhs); + + SearchFilter(const lldb::TargetSP &target_sp, unsigned char filterType); + + virtual ~SearchFilter(); + + SearchFilter &operator=(const SearchFilter &rhs); + + //------------------------------------------------------------------ + /// Call this method with a file spec to see if that spec passes the filter. + /// + /// @param[in] spec + /// The file spec to check against the filter. + /// @return + /// \b true if \a spec passes, and \b false otherwise. + //------------------------------------------------------------------ + virtual bool ModulePasses(const FileSpec &spec); + + //------------------------------------------------------------------ + /// Call this method with a Module to see if that module passes the filter. + /// + /// @param[in] module + /// The Module to check against the filter. + /// + /// @return + /// \b true if \a module passes, and \b false otherwise. + //------------------------------------------------------------------ + virtual bool ModulePasses(const lldb::ModuleSP &module_sp); + + //------------------------------------------------------------------ + /// Call this method with a Address to see if \a address passes the filter. + /// + /// @param[in] addr + /// The address to check against the filter. + /// + /// @return + /// \b true if \a address passes, and \b false otherwise. + //------------------------------------------------------------------ + virtual bool AddressPasses(Address &addr); + + //------------------------------------------------------------------ + /// Call this method with a FileSpec to see if \a file spec passes the filter + /// as the name of a compilation unit. + /// + /// @param[in] fileSpec + /// The file spec to check against the filter. + /// + /// @return + /// \b true if \a file spec passes, and \b false otherwise. + //------------------------------------------------------------------ + virtual bool CompUnitPasses(FileSpec &fileSpec); + + //------------------------------------------------------------------ + /// Call this method with a CompileUnit to see if \a comp unit passes the + /// filter. + /// + /// @param[in] compUnit + /// The CompileUnit to check against the filter. + /// + /// @return + /// \b true if \a Comp Unit passes, and \b false otherwise. + //------------------------------------------------------------------ + virtual bool CompUnitPasses(CompileUnit &compUnit); + + //------------------------------------------------------------------ + /// Call this method to do the search using the Searcher. + /// + /// @param[in] searcher + /// The searcher to drive with this search. + /// + //------------------------------------------------------------------ + virtual void Search(Searcher &searcher); + + //------------------------------------------------------------------ + /// Call this method to do the search using the Searcher in the module list + /// \a modules. + /// + /// @param[in] searcher + /// The searcher to drive with this search. + /// + /// @param[in] modules + /// The module list within which to restrict the search. + /// + //------------------------------------------------------------------ + virtual void SearchInModuleList(Searcher &searcher, ModuleList &modules); + + //------------------------------------------------------------------ + /// This determines which items are REQUIRED for the filter to pass. + /// For instance, if you are filtering by Compilation Unit, obviously + /// symbols that have no compilation unit can't pass So return + /// eSymbolContextCU + /// and search callbacks can then short cut the search to avoid looking at + /// things that obviously won't pass. + /// + /// @return + /// The required elements for the search, which is an or'ed together + /// set of lldb:SearchContextItem enum's. + /// + //------------------------------------------------------------------ + virtual uint32_t GetFilterRequiredItems(); + + //------------------------------------------------------------------ + /// Prints a canonical description for the search filter to the stream \a s. + /// + /// @param[in] s + /// Stream to which the output is copied. + //------------------------------------------------------------------ + virtual void GetDescription(Stream *s); + + //------------------------------------------------------------------ + /// Standard "Dump" method. At present it does nothing. + //------------------------------------------------------------------ + virtual void Dump(Stream *s) const; + + lldb::SearchFilterSP CopyForBreakpoint(Breakpoint &breakpoint); + + static lldb::SearchFilterSP + CreateFromStructuredData(Target &target, + const StructuredData::Dictionary &data_dict, + Status &error); + + virtual StructuredData::ObjectSP SerializeToStructuredData() { + return StructuredData::ObjectSP(); + } + + static const char *GetSerializationKey() { return "SearchFilter"; } + + static const char *GetSerializationSubclassKey() { return "Type"; } + + static const char *GetSerializationSubclassOptionsKey() { return "Options"; } + + enum FilterTy { + Unconstrained = 0, + Exception, + ByModule, + ByModules, + ByModulesAndCU, + LastKnownFilterType = ByModulesAndCU, + UnknownFilter + }; + + static const char *g_ty_to_name[LastKnownFilterType + 2]; + + enum FilterTy GetFilterTy() { + if (SubclassID > FilterTy::LastKnownFilterType) + return FilterTy::UnknownFilter; + else + return (enum FilterTy)SubclassID; + } + + const char *GetFilterName() { return FilterTyToName(GetFilterTy()); } + + static const char *FilterTyToName(enum FilterTy); + + static FilterTy NameToFilterTy(llvm::StringRef name); + +protected: + // Serialization of SearchFilter options: + enum OptionNames { ModList = 0, CUList, LanguageName, LastOptionName }; + static const char *g_option_names[LastOptionName]; + + static const char *GetKey(enum OptionNames enum_value) { + return g_option_names[enum_value]; + } + + StructuredData::DictionarySP + WrapOptionsDict(StructuredData::DictionarySP options_dict_sp); + + void SerializeFileSpecList(StructuredData::DictionarySP &options_dict_sp, + OptionNames name, FileSpecList &file_list); + + // 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); + + virtual lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) = 0; + + void SetTarget(lldb::TargetSP &target_sp) { m_target_sp = target_sp; } + + 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. +private: + unsigned char SubclassID; +}; + +//---------------------------------------------------------------------- +/// @class SearchFilterForUnconstrainedSearches SearchFilter.h +/// "lldb/Core/SearchFilter.h" +/// @brief This is a SearchFilter that searches through all modules. It also +/// consults the Target::ModuleIsExcludedForUnconstrainedSearches. +//---------------------------------------------------------------------- +class SearchFilterForUnconstrainedSearches : public SearchFilter { +public: + SearchFilterForUnconstrainedSearches(const lldb::TargetSP &target_sp) + : SearchFilter(target_sp, FilterTy::Unconstrained) {} + + ~SearchFilterForUnconstrainedSearches() override = default; + + bool ModulePasses(const FileSpec &module_spec) override; + + bool ModulePasses(const lldb::ModuleSP &module_sp) override; + + static lldb::SearchFilterSP + CreateFromStructuredData(Target &target, + const StructuredData::Dictionary &data_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + +protected: + lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override; +}; + +//---------------------------------------------------------------------- +/// @class SearchFilterByModule SearchFilter.h "lldb/Core/SearchFilter.h" +/// @brief This is a SearchFilter that restricts the search to a given module. +//---------------------------------------------------------------------- + +class SearchFilterByModule : public SearchFilter { +public: + //------------------------------------------------------------------ + /// The basic constructor takes a Target, which gives the space to search, + /// and the module to restrict the search to. + /// + /// @param[in] target + /// The Target that provides the module list to search. + /// + /// @param[in] module + /// The Module that limits the search. + //------------------------------------------------------------------ + SearchFilterByModule(const lldb::TargetSP &targetSP, const FileSpec &module); + + SearchFilterByModule(const SearchFilterByModule &rhs); + + ~SearchFilterByModule() override; + + SearchFilterByModule &operator=(const SearchFilterByModule &rhs); + + bool ModulePasses(const lldb::ModuleSP &module_sp) override; + + bool ModulePasses(const FileSpec &spec) override; + + bool AddressPasses(Address &address) override; + + bool CompUnitPasses(FileSpec &fileSpec) override; + + bool CompUnitPasses(CompileUnit &compUnit) override; + + void GetDescription(Stream *s) override; + + uint32_t GetFilterRequiredItems() override; + + void Dump(Stream *s) const override; + + void Search(Searcher &searcher) override; + + static lldb::SearchFilterSP + CreateFromStructuredData(Target &target, + const StructuredData::Dictionary &data_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + +protected: + lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override; + +private: + FileSpec m_module_spec; +}; + +class SearchFilterByModuleList : public SearchFilter { +public: + //------------------------------------------------------------------ + /// The basic constructor takes a Target, which gives the space to search, + /// and the module list to restrict the search to. + /// + /// @param[in] target + /// The Target that provides the module list to search. + /// + /// @param[in] module + /// The Module that limits the search. + //------------------------------------------------------------------ + SearchFilterByModuleList(const lldb::TargetSP &targetSP, + const FileSpecList &module_list); + + SearchFilterByModuleList(const lldb::TargetSP &targetSP, + const FileSpecList &module_list, + enum FilterTy filter_ty); + + SearchFilterByModuleList(const SearchFilterByModuleList &rhs); + + ~SearchFilterByModuleList() override; + + SearchFilterByModuleList &operator=(const SearchFilterByModuleList &rhs); + + bool ModulePasses(const lldb::ModuleSP &module_sp) override; + + bool ModulePasses(const FileSpec &spec) override; + + bool AddressPasses(Address &address) override; + + bool CompUnitPasses(FileSpec &fileSpec) override; + + bool CompUnitPasses(CompileUnit &compUnit) override; + + void GetDescription(Stream *s) override; + + uint32_t GetFilterRequiredItems() override; + + void Dump(Stream *s) const override; + + void Search(Searcher &searcher) override; + + static lldb::SearchFilterSP + CreateFromStructuredData(Target &target, + const StructuredData::Dictionary &data_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + + void SerializeUnwrapped(StructuredData::DictionarySP &options_dict_sp); + +protected: + lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override; + +protected: + FileSpecList m_module_spec_list; +}; + +class SearchFilterByModuleListAndCU : public SearchFilterByModuleList { +public: + //------------------------------------------------------------------ + /// The basic constructor takes a Target, which gives the space to search, + /// and the module list to restrict the search to. + /// + /// @param[in] target + /// The Target that provides the module list to search. + /// + /// @param[in] module + /// The Module that limits the search. + //------------------------------------------------------------------ + SearchFilterByModuleListAndCU(const lldb::TargetSP &targetSP, + const FileSpecList &module_list, + const FileSpecList &cu_list); + + SearchFilterByModuleListAndCU(const SearchFilterByModuleListAndCU &rhs); + + ~SearchFilterByModuleListAndCU() override; + + SearchFilterByModuleListAndCU & + operator=(const SearchFilterByModuleListAndCU &rhs); + + bool AddressPasses(Address &address) override; + + bool CompUnitPasses(FileSpec &fileSpec) override; + + bool CompUnitPasses(CompileUnit &compUnit) override; + + void GetDescription(Stream *s) override; + + uint32_t GetFilterRequiredItems() override; + + void Dump(Stream *s) const override; + + void Search(Searcher &searcher) override; + + static lldb::SearchFilterSP + CreateFromStructuredData(Target &target, + const StructuredData::Dictionary &data_dict, + Status &error); + + StructuredData::ObjectSP SerializeToStructuredData() override; + +protected: + lldb::SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override; + +private: + FileSpecList m_cu_spec_list; +}; + +} // namespace lldb_private + +#endif // liblldb_SearchFilter_h_ diff --git a/include/lldb/Core/Section.h b/include/lldb/Core/Section.h new file mode 100644 index 000000000..0466693ed --- /dev/null +++ b/include/lldb/Core/Section.h @@ -0,0 +1,287 @@ +//===-- 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/Core/ModuleChild.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Flags.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for SectionType +#include "lldb/lldb-forward.h" // for SectionSP, ModuleSP, SectionWP +#include "lldb/lldb-types.h" // for addr_t, offset_t, user_id_t + +#include // for enable_shared_from_this +#include // for vector + +#include // for size_t +#include // for uint32_t, UINT32_MAX + +namespace lldb_private { +class Address; +} +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class ObjectFile; +} +namespace lldb_private { +class Section; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class Target; +} + +namespace lldb_private { + +class SectionList { +public: + typedef std::vector collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + + SectionList(); + + ~SectionList(); + + SectionList &operator=(const SectionList &rhs); + + size_t AddSection(const lldb::SectionSP §ion_sp); + + size_t AddUniqueSection(const lldb::SectionSP §ion_sp); + + size_t FindSectionIndex(const Section *sect); + + bool ContainsSection(lldb::user_id_t sect_id) const; + + void Dump(Stream *s, Target *target, bool show_header, uint32_t depth) const; + + lldb::SectionSP FindSectionByName(const ConstString §ion_dstr) const; + + lldb::SectionSP FindSectionByID(lldb::user_id_t sect_id) const; + + lldb::SectionSP FindSectionByType(lldb::SectionType sect_type, + bool check_children, + size_t start_idx = 0) const; + + lldb::SectionSP + FindSectionContainingFileAddress(lldb::addr_t addr, + uint32_t depth = UINT32_MAX) const; + + // Get the number of sections in this list only + size_t GetSize() const { return m_sections.size(); } + + // Get the number of sections in this list, and any contained child sections + size_t GetNumSections(uint32_t depth) const; + + bool ReplaceSection(lldb::user_id_t sect_id, + const lldb::SectionSP §ion_sp, + uint32_t depth = UINT32_MAX); + + // Warning, this can be slow as it's removing items from a std::vector. + bool DeleteSection(size_t idx); + + lldb::SectionSP GetSectionAtIndex(size_t idx) const; + + size_t Slide(lldb::addr_t slide_amount, bool slide_children); + + void Clear() { m_sections.clear(); } + +protected: + collection m_sections; +}; + +class Section : public std::enable_shared_from_this
, + public ModuleChild, + public UserID, + public Flags { +public: + // Create a root section (one that has no parent) + Section(const lldb::ModuleSP &module_sp, ObjectFile *obj_file, + lldb::user_id_t sect_id, const ConstString &name, + lldb::SectionType sect_type, lldb::addr_t file_vm_addr, + lldb::addr_t vm_size, lldb::offset_t file_offset, + lldb::offset_t file_size, uint32_t log2align, uint32_t flags, + uint32_t target_byte_size = 1); + + // Create a section that is a child of parent_section_sp + Section(const lldb::SectionSP &parent_section_sp, // NULL for top level + // sections, non-NULL for + // child sections + const lldb::ModuleSP &module_sp, ObjectFile *obj_file, + lldb::user_id_t sect_id, const ConstString &name, + lldb::SectionType sect_type, lldb::addr_t file_vm_addr, + lldb::addr_t vm_size, lldb::offset_t file_offset, + lldb::offset_t file_size, uint32_t log2align, uint32_t flags, + uint32_t target_byte_size = 1); + + ~Section(); + + static int Compare(const Section &a, const Section &b); + + bool ContainsFileAddress(lldb::addr_t vm_addr) const; + + SectionList &GetChildren() { return m_children; } + + const SectionList &GetChildren() const { return m_children; } + + void Dump(Stream *s, Target *target, uint32_t depth) const; + + void DumpName(Stream *s) const; + + lldb::addr_t GetLoadBaseAddress(Target *target) const; + + bool ResolveContainedAddress(lldb::addr_t offset, Address &so_addr, + bool allow_section_end = false) const; + + lldb::offset_t GetFileOffset() const { return m_file_offset; } + + void SetFileOffset(lldb::offset_t file_offset) { + m_file_offset = file_offset; + } + + lldb::offset_t GetFileSize() const { return m_file_size; } + + void SetFileSize(lldb::offset_t file_size) { m_file_size = file_size; } + + lldb::addr_t GetFileAddress() const; + + bool SetFileAddress(lldb::addr_t file_addr); + + lldb::addr_t GetOffset() const; + + lldb::addr_t GetByteSize() const { return m_byte_size; } + + void SetByteSize(lldb::addr_t byte_size) { m_byte_size = byte_size; } + + bool IsFake() const { return m_fake; } + + void SetIsFake(bool fake) { m_fake = fake; } + + bool IsEncrypted() const { return m_encrypted; } + + void SetIsEncrypted(bool b) { m_encrypted = b; } + + bool IsDescendant(const Section *section); + + const ConstString &GetName() const { return m_name; } + + bool Slide(lldb::addr_t slide_amount, bool slide_children); + + lldb::SectionType GetType() const { return m_type; } + + lldb::SectionSP GetParent() const { return m_parent_wp.lock(); } + + bool IsThreadSpecific() const { return m_thread_specific; } + + void SetIsThreadSpecific(bool b) { m_thread_specific = b; } + + //------------------------------------------------------------------ + /// Get the permissions as OR'ed bits from lldb::Permissions + //------------------------------------------------------------------ + uint32_t GetPermissions() const; + + //------------------------------------------------------------------ + /// Set the permissions using bits OR'ed from lldb::Permissions + //------------------------------------------------------------------ + void SetPermissions(uint32_t permissions); + + ObjectFile *GetObjectFile() { return m_obj_file; } + const ObjectFile *GetObjectFile() const { return m_obj_file; } + + //------------------------------------------------------------------ + /// Read the section data from the object file that the section + /// resides in. + /// + /// @param[in] dst + /// Where to place the data + /// + /// @param[in] dst_len + /// How many bytes of section data to read + /// + /// @param[in] offset + /// The offset in bytes within this section's data at which to + /// start copying data from. + /// + /// @return + /// The number of bytes read from the section, or zero if the + /// section has no data or \a offset is not a valid offset + /// in this section. + //------------------------------------------------------------------ + lldb::offset_t GetSectionData(void *dst, lldb::offset_t dst_len, + lldb::offset_t offset = 0); + + //------------------------------------------------------------------ + /// Get the shared reference to the section data from the object + /// file that the section resides in. No copies of the data will be + /// make unless the object file has been read from memory. If the + /// object file is on disk, it will shared the mmap data for the + /// entire object file. + /// + /// @param[in] data + /// Where to place the data, address byte size, and byte order + /// + /// @return + /// The number of bytes read from the section, or zero if the + /// section has no data or \a offset is not a valid offset + /// in this section. + //------------------------------------------------------------------ + lldb::offset_t GetSectionData(DataExtractor &data) const; + + uint32_t GetLog2Align() { return m_log2align; } + + void SetLog2Align(uint32_t align) { m_log2align = align; } + + // Get the number of host bytes required to hold a target byte + uint32_t GetTargetByteSize() const { return m_target_byte_size; } + +protected: + ObjectFile *m_obj_file; // The object file that data for this section should + // be read from + lldb::SectionType m_type; // The type of this section + lldb::SectionWP m_parent_wp; // Weak pointer to parent section + ConstString m_name; // Name of this section + lldb::addr_t m_file_addr; // The absolute file virtual address range of this + // section if m_parent == NULL, + // offset from parent file virtual address if m_parent != NULL + lldb::addr_t m_byte_size; // Size in bytes that this section will occupy in + // memory at runtime + lldb::offset_t m_file_offset; // Object file offset (if any) + lldb::offset_t m_file_size; // Object file size (can be smaller than + // m_byte_size for zero filled sections...) + uint32_t m_log2align; // log_2(align) of the section (i.e. section has to be + // aligned to 2^m_log2align) + SectionList m_children; // Child sections + bool m_fake : 1, // If true, then this section only can contain the address if + // one of its + // children contains an address. This allows for gaps between the children + // that are contained in the address range for this section, but do not + // produce + // hits unless the children contain the address. + m_encrypted : 1, // Set to true if the contents are encrypted + m_thread_specific : 1, // This section is thread specific + m_readable : 1, // If this section has read permissions + m_writable : 1, // If this section has write permissions + m_executable : 1; // If this section has executable permissions + uint32_t m_target_byte_size; // Some architectures have non-8-bit byte size. + // This is specified as + // as a multiple number of a host bytes +private: + DISALLOW_COPY_AND_ASSIGN(Section); +}; + +} // namespace lldb_private + +#endif // liblldb_Section_h_ diff --git a/include/lldb/Core/SourceManager.h b/include/lldb/Core/SourceManager.h new file mode 100644 index 000000000..053badf64 --- /dev/null +++ b/include/lldb/Core/SourceManager.h @@ -0,0 +1,184 @@ +//===-- 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_ + +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-forward.h" // for DebuggerSP, DebuggerWP, DataBufferSP + +#include "llvm/Support/Chrono.h" + +#include // for uint32_t, UINT32_MAX +#include +#include +#include // for size_t +#include // for string +#include + +namespace lldb_private { +class RegularExpression; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContextList; +} +namespace lldb_private { +class Target; +} + +namespace lldb_private { + +class SourceManager { +public: +#ifndef SWIG + class File { + friend bool operator==(const SourceManager::File &lhs, + const SourceManager::File &rhs); + + public: + File(const FileSpec &file_spec, Target *target); + File(const FileSpec &file_spec, lldb::DebuggerSP debugger_sp); + ~File() = default; + + void UpdateIfNeeded(); + + size_t DisplaySourceLines(uint32_t line, uint32_t column, + uint32_t context_before, uint32_t context_after, + Stream *s); + void FindLinesMatchingRegex(RegularExpression ®ex, uint32_t start_line, + uint32_t end_line, + std::vector &match_lines); + + bool GetLine(uint32_t line_no, std::string &buffer); + + uint32_t GetLineOffset(uint32_t line); + + bool LineIsValid(uint32_t line); + + bool FileSpecMatches(const FileSpec &file_spec); + + const FileSpec &GetFileSpec() { return m_file_spec; } + + uint32_t GetSourceMapModificationID() const { return m_source_map_mod_id; } + + const char *PeekLineData(uint32_t line); + + uint32_t GetLineLength(uint32_t line, bool include_newline_chars); + + uint32_t GetNumLines(); + + protected: + bool CalculateLineOffsets(uint32_t line = UINT32_MAX); + + FileSpec m_file_spec_orig; // The original file spec that was used (can be + // different from m_file_spec) + FileSpec m_file_spec; // The actually file spec being used (if the target + // has source mappings, this might be different from + // m_file_spec_orig) + + // Keep the modification time that this file data is valid for + llvm::sys::TimePoint<> m_mod_time; + + // If the target uses path remappings, be sure to clear our notion of a + // source file if the path modification ID changes + uint32_t m_source_map_mod_id = 0; + lldb::DataBufferSP m_data_sp; + typedef std::vector LineOffsets; + LineOffsets m_offsets; + lldb::DebuggerWP m_debugger_wp; + + private: + void CommonInitializer(const FileSpec &file_spec, Target *target); + }; +#endif // SWIG + + typedef std::shared_ptr FileSP; + +#ifndef SWIG + // The SourceFileCache class separates the source manager from the cache of + // source files, so the + // cache can be stored in the Debugger, but the source managers can be per + // target. + class SourceFileCache { + public: + SourceFileCache() = default; + ~SourceFileCache() = default; + + void AddSourceFile(const FileSP &file_sp); + FileSP FindSourceFile(const FileSpec &file_spec) const; + + protected: + typedef std::map FileCache; + FileCache m_file_cache; + }; +#endif // SWIG + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + // A source manager can be made with a non-null target, in which case it can + // use the path remappings to find + // source files that are not in their build locations. With no target it + // won't be able to do this. + SourceManager(const lldb::DebuggerSP &debugger_sp); + SourceManager(const lldb::TargetSP &target_sp); + + ~SourceManager(); + + FileSP GetLastFile() { return m_last_file_sp; } + + size_t + DisplaySourceLinesWithLineNumbers(const FileSpec &file, uint32_t line, + uint32_t column, uint32_t context_before, + uint32_t context_after, + const char *current_line_cstr, Stream *s, + const SymbolContextList *bp_locs = nullptr); + + // This variant uses the last file we visited. + size_t DisplaySourceLinesWithLineNumbersUsingLastFile( + uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column, + const char *current_line_cstr, Stream *s, + const SymbolContextList *bp_locs = nullptr); + + size_t DisplayMoreWithLineNumbers(Stream *s, uint32_t count, bool reverse, + const SymbolContextList *bp_locs = nullptr); + + bool SetDefaultFileAndLine(const FileSpec &file_spec, uint32_t line); + + bool GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line); + + bool DefaultFileAndLineSet() { return (m_last_file_sp.get() != nullptr); } + + void FindLinesMatchingRegex(FileSpec &file_spec, RegularExpression ®ex, + uint32_t start_line, uint32_t end_line, + std::vector &match_lines); + + FileSP GetFile(const FileSpec &file_spec); + +protected: + FileSP m_last_file_sp; + uint32_t m_last_line; + uint32_t m_last_count; + bool m_default_set; + lldb::TargetWP m_target_wp; + lldb::DebuggerWP m_debugger_wp; + +private: + DISALLOW_COPY_AND_ASSIGN(SourceManager); +}; + +bool operator==(const SourceManager::File &lhs, const SourceManager::File &rhs); + +} // namespace lldb_private + +#endif // liblldb_SourceManager_h_ diff --git a/include/lldb/Core/State.h b/include/lldb/Core/State.h new file mode 100644 index 000000000..68f0fee25 --- /dev/null +++ b/include/lldb/Core/State.h @@ -0,0 +1,85 @@ +//===-- 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_ + +#include "llvm/Support/FormatProviders.h" + +#include "lldb/lldb-enumerations.h" // for StateType +#include "llvm/ADT/StringRef.h" // for StringRef +#include "llvm/Support/raw_ostream.h" // for raw_ostream + +#include // for uint32_t + +namespace lldb_private { + +//------------------------------------------------------------------ +/// Converts a StateType to a C string. +/// +/// @param[in] state +/// The StateType object to convert. +/// +/// @return +/// A NULL terminated C string that describes \a state. The +/// returned string comes from constant string buffers and does +/// not need to be freed. +//------------------------------------------------------------------ +const char *StateAsCString(lldb::StateType state); + +//------------------------------------------------------------------ +/// Check if a state represents a state where the process or thread +/// is running. +/// +/// @param[in] state +/// The StateType enumeration value +/// +/// @return +/// \b true if the state represents a process or thread state +/// where the process or thread is running, \b false otherwise. +//------------------------------------------------------------------ +bool StateIsRunningState(lldb::StateType state); + +//------------------------------------------------------------------ +/// Check if a state represents a state where the process or thread +/// is stopped. Stopped can mean stopped when the process is still +/// around, or stopped when the process has exited or doesn't exist +/// yet. The \a must_exist argument tells us which of these cases is +/// desired. +/// +/// @param[in] state +/// The StateType enumeration value +/// +/// @param[in] must_exist +/// A boolean that indicates the thread must also be alive +/// so states like unloaded or exited won't return true. +/// +/// @return +/// \b true if the state represents a process or thread state +/// where the process or thread is stopped. If \a must_exist is +/// \b true, then the process can't be exited or unloaded, +/// otherwise exited and unloaded or other states where the +/// process no longer exists are considered to be stopped. +//------------------------------------------------------------------ +bool StateIsStoppedState(lldb::StateType state, bool must_exist); + +const char *GetPermissionsAsCString(uint32_t permissions); + +} // namespace lldb_private + +namespace llvm { +template <> struct format_provider { + static void format(const lldb::StateType &state, raw_ostream &Stream, + StringRef Style) { + Stream << lldb_private::StateAsCString(state); + } +}; +} + +#endif // liblldb_State_h_ diff --git a/include/lldb/Core/StreamAsynchronousIO.h b/include/lldb/Core/StreamAsynchronousIO.h new file mode 100644 index 000000000..29b109757 --- /dev/null +++ b/include/lldb/Core/StreamAsynchronousIO.h @@ -0,0 +1,43 @@ +//===-- StreamAsynchronousIO.h -----------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_StreamAsynchronousIO_h_ +#define liblldb_StreamAsynchronousIO_h_ + +#include "lldb/Utility/Stream.h" + +#include + +#include // for size_t + +namespace lldb_private { +class Debugger; +} + +namespace lldb_private { + +class StreamAsynchronousIO : public Stream { +public: + StreamAsynchronousIO(Debugger &debugger, bool for_stdout); + + ~StreamAsynchronousIO() override; + + void Flush() override; + + size_t Write(const void *src, size_t src_len) override; + +private: + Debugger &m_debugger; + std::string m_data; + bool m_for_stdout; +}; + +} // namespace lldb_private + +#endif // liblldb_StreamAsynchronousIO_h diff --git a/include/lldb/Core/StreamBuffer.h b/include/lldb/Core/StreamBuffer.h new file mode 100644 index 000000000..3b1857302 --- /dev/null +++ b/include/lldb/Core/StreamBuffer.h @@ -0,0 +1,56 @@ +//===-- StreamBuffer.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_StreamBuffer_h_ +#define liblldb_StreamBuffer_h_ + +#include "lldb/Utility/Stream.h" +#include "llvm/ADT/SmallVector.h" +#include +#include + +namespace lldb_private { + +template class StreamBuffer : public Stream { +public: + StreamBuffer() : Stream(0, 4, lldb::eByteOrderBig), m_packet() {} + + StreamBuffer(uint32_t flags, uint32_t addr_size, lldb::ByteOrder byte_order) + : Stream(flags, addr_size, byte_order), m_packet() {} + + virtual ~StreamBuffer() {} + + virtual void Flush() { + // Nothing to do when flushing a buffer based stream... + } + + virtual size_t Write(const void *s, size_t length) { + if (s && length) + m_packet.append((const char *)s, ((const char *)s) + length); + return length; + } + + void Clear() { m_packet.clear(); } + + // Beware, this might not be NULL terminated as you can expect from + // StringString as there may be random bits in the llvm::SmallVector. If + // you are using this class to create a C string, be sure the call PutChar + // ('\0') + // after you have created your string, or use StreamString. + const char *GetData() const { return m_packet.data(); } + + size_t GetSize() const { return m_packet.size(); } + +protected: + llvm::SmallVector m_packet; +}; + +} // namespace lldb_private + +#endif // #ifndef liblldb_StreamBuffer_h_ diff --git a/include/lldb/Core/StreamFile.h b/include/lldb/Core/StreamFile.h new file mode 100644 index 000000000..a26ae84c7 --- /dev/null +++ b/include/lldb/Core/StreamFile.h @@ -0,0 +1,63 @@ +//===-- 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_ + +#include "lldb/Host/File.h" +#include "lldb/Utility/Stream.h" +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for FilePermissions::eFilePermission... + +#include // for uint32_t +#include // for size_t, FILE + +namespace lldb_private { + +class StreamFile : public Stream { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + StreamFile(); + + StreamFile(uint32_t flags, uint32_t addr_size, lldb::ByteOrder byte_order); + + StreamFile(int fd, bool transfer_ownership); + + StreamFile(const char *path); + + StreamFile(const char *path, uint32_t options, + uint32_t permissions = lldb::eFilePermissionsFileDefault); + + StreamFile(FILE *fh, bool transfer_ownership); + + ~StreamFile() override; + + File &GetFile() { return m_file; } + + const File &GetFile() const { return m_file; } + + void Flush() override; + + size_t Write(const void *s, size_t length) override; + +protected: + //------------------------------------------------------------------ + // Classes that inherit from StreamFile can see and modify these + //------------------------------------------------------------------ + File m_file; + +private: + DISALLOW_COPY_AND_ASSIGN(StreamFile); +}; + +} // namespace lldb_private + +#endif // liblldb_StreamFile_h_ diff --git a/include/lldb/Core/StructuredDataImpl.h b/include/lldb/Core/StructuredDataImpl.h new file mode 100644 index 000000000..819d1d9e5 --- /dev/null +++ b/include/lldb/Core/StructuredDataImpl.h @@ -0,0 +1,156 @@ +//===-- StructuredDataImpl.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_StructuredDataImpl_h_ +#define liblldb_StructuredDataImpl_h_ + +#include "lldb/Core/Event.h" +#include "lldb/Target/StructuredDataPlugin.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "llvm/ADT/StringRef.h" + +#pragma mark-- +#pragma mark StructuredDataImpl + +namespace lldb_private { + +class StructuredDataImpl { +public: + StructuredDataImpl() : m_plugin_wp(), m_data_sp() {} + + StructuredDataImpl(const StructuredDataImpl &rhs) = default; + + StructuredDataImpl(const lldb::EventSP &event_sp) + : m_plugin_wp( + EventDataStructuredData::GetPluginFromEvent(event_sp.get())), + m_data_sp(EventDataStructuredData::GetObjectFromEvent(event_sp.get())) { + } + + ~StructuredDataImpl() = default; + + StructuredDataImpl &operator=(const StructuredDataImpl &rhs) = default; + + bool IsValid() const { return m_data_sp.get() != nullptr; } + + void Clear() { + m_plugin_wp.reset(); + m_data_sp.reset(); + } + + Status GetAsJSON(Stream &stream) const { + Status error; + + if (!m_data_sp) { + error.SetErrorString("No structured data."); + return error; + } + + m_data_sp->Dump(stream); + return error; + } + + Status GetDescription(Stream &stream) const { + Status error; + + if (!m_data_sp) { + error.SetErrorString("Cannot pretty print structured data: " + "no data to print."); + return error; + } + + // Grab the plugin. + auto plugin_sp = lldb::StructuredDataPluginSP(m_plugin_wp); + if (!plugin_sp) { + error.SetErrorString("Cannot pretty print structured data: " + "plugin doesn't exist."); + return error; + } + + // Get the data's description. + return plugin_sp->GetDescription(m_data_sp, stream); + } + + StructuredData::ObjectSP GetObjectSP() { return m_data_sp; } + + void SetObjectSP(const StructuredData::ObjectSP &obj) { m_data_sp = obj; } + + lldb::StructuredDataType GetType() const { + return (m_data_sp ? m_data_sp->GetType() : + lldb::eStructuredDataTypeInvalid); + } + + size_t GetSize() const { + if (!m_data_sp) + return 0; + + if (m_data_sp->GetType() == lldb::eStructuredDataTypeDictionary) { + auto dict = m_data_sp->GetAsDictionary(); + return (dict->GetSize()); + } else if (m_data_sp->GetType() == lldb::eStructuredDataTypeArray) { + auto array = m_data_sp->GetAsArray(); + return (array->GetSize()); + } else + return 0; + } + + StructuredData::ObjectSP GetValueForKey(const char *key) const { + if (m_data_sp) { + auto dict = m_data_sp->GetAsDictionary(); + if (dict) + return dict->GetValueForKey(llvm::StringRef(key)); + } + return StructuredData::ObjectSP(); + } + + StructuredData::ObjectSP GetItemAtIndex(size_t idx) const { + if (m_data_sp) { + auto array = m_data_sp->GetAsArray(); + if (array) + return array->GetItemAtIndex(idx); + } + return StructuredData::ObjectSP(); + } + + uint64_t GetIntegerValue(uint64_t fail_value = 0) const { + return (m_data_sp ? m_data_sp->GetIntegerValue(fail_value) : fail_value); + } + + double GetFloatValue(double fail_value = 0.0) const { + return (m_data_sp ? m_data_sp->GetFloatValue(fail_value) : fail_value); + } + + bool GetBooleanValue(bool fail_value = false) const { + return (m_data_sp ? m_data_sp->GetBooleanValue(fail_value) : fail_value); + } + + size_t GetStringValue(char *dst, size_t dst_len) const { + if (!m_data_sp) + return 0; + + llvm::StringRef result = m_data_sp->GetStringValue(); + if (result.empty()) + return 0; + + if (!dst || !dst_len) { + char s[1]; + return (::snprintf(s, 1, "%s", result.data())); + } + return (::snprintf(dst, dst_len, "%s", result.data())); + } + +private: + lldb::StructuredDataPluginWP m_plugin_wp; + StructuredData::ObjectSP m_data_sp; +}; +} // namespace lldb_private +#endif diff --git a/include/lldb/Core/ThreadSafeDenseMap.h b/include/lldb/Core/ThreadSafeDenseMap.h new file mode 100644 index 000000000..9b52e0355 --- /dev/null +++ b/include/lldb/Core/ThreadSafeDenseMap.h @@ -0,0 +1,70 @@ +//===-- ThreadSafeDenseMap.h ------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadSafeDenseMap_h_ +#define liblldb_ThreadSafeDenseMap_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "llvm/ADT/DenseMap.h" + +// Project includes + +namespace lldb_private { + +template +class ThreadSafeDenseMap { +public: + typedef llvm::DenseMap<_KeyType, _ValueType> LLVMMapType; + + ThreadSafeDenseMap(unsigned map_initial_capacity = 0) + : m_map(map_initial_capacity), m_mutex() {} + + void Insert(_KeyType k, _ValueType v) { + std::lock_guard<_MutexType> guard(m_mutex); + m_map.insert(std::make_pair(k, v)); + } + + void Erase(_KeyType k) { + std::lock_guard<_MutexType> guard(m_mutex); + m_map.erase(k); + } + + _ValueType Lookup(_KeyType k) { + std::lock_guard<_MutexType> guard(m_mutex); + return m_map.lookup(k); + } + + bool Lookup(_KeyType k, _ValueType &v) { + std::lock_guard<_MutexType> guard(m_mutex); + auto iter = m_map.find(k), end = m_map.end(); + if (iter == end) + return false; + v = iter->second; + return true; + } + + void Clear() { + std::lock_guard<_MutexType> guard(m_mutex); + m_map.clear(); + } + +protected: + LLVMMapType m_map; + _MutexType m_mutex; +}; + +} // namespace lldb_private + +#endif // liblldb_ThreadSafeSTLMap_h_ diff --git a/include/lldb/Core/ThreadSafeDenseSet.h b/include/lldb/Core/ThreadSafeDenseSet.h new file mode 100644 index 000000000..49c55e96a --- /dev/null +++ b/include/lldb/Core/ThreadSafeDenseSet.h @@ -0,0 +1,60 @@ +//===-- ThreadSafeDenseSet.h ------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadSafeDenseSet_h_ +#define liblldb_ThreadSafeDenseSet_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "llvm/ADT/DenseSet.h" + +// Project includes + +namespace lldb_private { + +template +class ThreadSafeDenseSet { +public: + typedef llvm::DenseSet<_ElementType> LLVMSetType; + + ThreadSafeDenseSet(unsigned set_initial_capacity = 0) + : m_set(set_initial_capacity), m_mutex() {} + + void Insert(_ElementType e) { + std::lock_guard<_MutexType> guard(m_mutex); + m_set.insert(e); + } + + void Erase(_ElementType e) { + std::lock_guard<_MutexType> guard(m_mutex); + m_set.erase(e); + } + + bool Lookup(_ElementType e) { + std::lock_guard<_MutexType> guard(m_mutex); + return (m_set.count(e) > 0); + } + + void Clear() { + stds::lock_guard<_MutexType> guard(m_mutex); + m_set.clear(); + } + +protected: + LLVMSetType m_set; + _MutexType m_mutex; +}; + +} // namespace lldb_private + +#endif // liblldb_ThreadSafeDenseSet_h_ diff --git a/include/lldb/Core/ThreadSafeSTLMap.h b/include/lldb/Core/ThreadSafeSTLMap.h new file mode 100644 index 000000000..5520920c4 --- /dev/null +++ b/include/lldb/Core/ThreadSafeSTLMap.h @@ -0,0 +1,137 @@ +//===-- 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 +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-defines.h" + +namespace lldb_private { + +template 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() {} + + ~ThreadSafeSTLMap() {} + + bool IsEmpty() const { + std::lock_guard guard(m_mutex); + return m_collection.empty(); + } + + void Clear() { + std::lock_guard guard(m_mutex); + return m_collection.clear(); + } + + size_t Erase(const _Key &key) { + std::lock_guard guard(m_mutex); + return EraseNoLock(key); + } + + size_t EraseNoLock(const _Key &key) { return m_collection.erase(key); } + + bool GetValueForKey(const _Key &key, _Tp &value) const { + std::lock_guard guard(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 { + std::lock_guard guard(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 { + std::lock_guard guard(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) { + std::lock_guard guard(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; + } + + std::recursive_mutex &GetMutex() { return m_mutex; } + +private: + collection m_collection; + mutable std::recursive_mutex m_mutex; + + //------------------------------------------------------------------ + // For ThreadSafeSTLMap only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ThreadSafeSTLMap); +}; + +} // namespace lldb_private + +#endif // liblldb_ThreadSafeSTLMap_h_ diff --git a/include/lldb/Core/ThreadSafeSTLVector.h b/include/lldb/Core/ThreadSafeSTLVector.h new file mode 100644 index 000000000..466f4309c --- /dev/null +++ b/include/lldb/Core/ThreadSafeSTLVector.h @@ -0,0 +1,81 @@ +//===-- ThreadSafeSTLVector.h ------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadSafeSTLVector_h_ +#define liblldb_ThreadSafeSTLVector_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-defines.h" + +namespace lldb_private { + +template class ThreadSafeSTLVector { +public: + typedef std::vector<_Object> collection; + typedef typename collection::iterator iterator; + typedef typename collection::const_iterator const_iterator; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + ThreadSafeSTLVector() : m_collection(), m_mutex() {} + + ~ThreadSafeSTLVector() = default; + + bool IsEmpty() const { + std::lock_guard guard(m_mutex); + return m_collection.empty(); + } + + void Clear() { + std::lock_guard guard(m_mutex); + return m_collection.clear(); + } + + size_t GetCount() { + std::lock_guard guard(m_mutex); + return m_collection.size(); + } + + void AppendObject(_Object &object) { + std::lock_guard guard(m_mutex); + m_collection.push_back(object); + } + + _Object GetObject(size_t index) { + std::lock_guard guard(m_mutex); + return m_collection.at(index); + } + + void SetObject(size_t index, const _Object &object) { + std::lock_guard guard(m_mutex); + m_collection.at(index) = object; + } + + std::recursive_mutex &GetMutex() { return m_mutex; } + +private: + collection m_collection; + mutable std::recursive_mutex m_mutex; + + //------------------------------------------------------------------ + // For ThreadSafeSTLVector only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ThreadSafeSTLVector); +}; + +} // namespace lldb_private + +#endif // liblldb_ThreadSafeSTLVector_h_ diff --git a/include/lldb/Core/ThreadSafeValue.h b/include/lldb/Core/ThreadSafeValue.h new file mode 100644 index 000000000..60eaf91c4 --- /dev/null +++ b/include/lldb/Core/ThreadSafeValue.h @@ -0,0 +1,69 @@ +//===-- 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 +#include + +// Other libraries and framework includes +// Project includes + +namespace lldb_private { + +template class ThreadSafeValue { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + ThreadSafeValue() : m_value(), m_mutex() {} + + ThreadSafeValue(const T &value) : m_value(value), m_mutex() {} + + ~ThreadSafeValue() {} + + T GetValue() const { + T value; + { + std::lock_guard guard(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) { + std::lock_guard guard(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; } + + std::recursive_mutex &GetMutex() { return m_mutex; } + +private: + T m_value; + mutable std::recursive_mutex m_mutex; + + //------------------------------------------------------------------ + // For ThreadSafeValue only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ThreadSafeValue); +}; + +} // namespace lldb_private +#endif // liblldb_ThreadSafeValue_h_ diff --git a/include/lldb/Core/UniqueCStringMap.h b/include/lldb/Core/UniqueCStringMap.h new file mode 100644 index 000000000..e8c6c7c13 --- /dev/null +++ b/include/lldb/Core/UniqueCStringMap.h @@ -0,0 +1,273 @@ +//===-- 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_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/RegularExpression.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +// Templatized uniqued string map. +// +// This map is useful for mapping unique C string names to values of +// type T. Each "const char *" name added must be unique for a given +// C string value. ConstString::GetCString() can provide such strings. +// Any other string table that has guaranteed unique values can also +// be used. +//---------------------------------------------------------------------- +template class UniqueCStringMap { +public: + struct Entry { + Entry() {} + + Entry(ConstString cstr) : cstring(cstr), value() {} + + Entry(ConstString cstr, const T &v) : cstring(cstr), value(v) {} + + // This is only for uniqueness, not lexicographical ordering, so we can + // just compare pointers. + bool operator<(const Entry &rhs) const { + return cstring.GetCString() < rhs.cstring.GetCString(); + } + + ConstString cstring; + T value; + }; + + //------------------------------------------------------------------ + // Call this function multiple times to add a bunch of entries to + // this map, then later call UniqueCStringMap::Sort() before doing + // any searches by name. + //------------------------------------------------------------------ + void Append(ConstString unique_cstr, const T &value) { + m_map.push_back(typename UniqueCStringMap::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(ConstString unique_cstr, const T &value) { + typename UniqueCStringMap::Entry e(unique_cstr, value); + m_map.insert(std::upper_bound(m_map.begin(), m_map.end(), e), e); + } + + void Insert(const Entry &e) { + m_map.insert(std::upper_bound(m_map.begin(), m_map.end(), e), e); + } + + //------------------------------------------------------------------ + // Get an entries by index in a variety of forms. + // + // The caller is responsible for ensuring that the collection does + // not change during while using the returned values. + //------------------------------------------------------------------ + bool GetValueAtIndex(uint32_t idx, T &value) const { + if (idx < m_map.size()) { + value = m_map[idx].value; + return true; + } + return false; + } + + ConstString GetCStringAtIndexUnchecked(uint32_t idx) const { + return m_map[idx].cstring; + } + + // Use this function if you have simple types in your map that you + // can easily copy when accessing values by index. + T GetValueAtIndexUnchecked(uint32_t idx) const { return m_map[idx].value; } + + // Use this function if you have complex types in your map that you + // don't want to copy when accessing values by index. + const T &GetValueRefAtIndexUnchecked(uint32_t idx) const { + return m_map[idx].value; + } + + ConstString GetCStringAtIndex(uint32_t idx) const { + return ((idx < m_map.size()) ? m_map[idx].cstring : ConstString()); + } + + //------------------------------------------------------------------ + // Find the value for the unique string in the map. + // + // Return the value for \a unique_cstr if one is found, return + // \a fail_value otherwise. This method works well for simple type + // T values and only if there is a sensible failure value that can + // be returned and that won't match any existing values. + //------------------------------------------------------------------ + T Find(ConstString unique_cstr, T fail_value) const { + Entry search_entry(unique_cstr); + const_iterator end = m_map.end(); + const_iterator pos = std::lower_bound(m_map.begin(), end, search_entry); + if (pos != end) { + if (pos->cstring == unique_cstr) + return pos->value; + } + return fail_value; + } + + //------------------------------------------------------------------ + // Get a pointer to the first entry that matches "name". nullptr 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(ConstString 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 && pos->cstring == unique_cstr) + return &(*pos); + return nullptr; + } + + //------------------------------------------------------------------ + // Get a pointer to the next entry that matches "name" from a + // previously returned Entry pointer. nullptr will be returned if there + // is no subsequent entry that matches "name". + // + // The caller is responsible for ensuring that the collection does + // not change during while using the returned pointer. + //------------------------------------------------------------------ + const Entry *FindNextValueForName(const Entry *entry_ptr) const { + if (!m_map.empty()) { + const Entry *first_entry = &m_map[0]; + const Entry *after_last_entry = first_entry + m_map.size(); + const Entry *next_entry = entry_ptr + 1; + if (first_entry <= next_entry && next_entry < after_last_entry) { + if (next_entry->cstring == entry_ptr->cstring) + return next_entry; + } + } + return nullptr; + } + + size_t GetValues(ConstString unique_cstr, std::vector &values) const { + const size_t start_size = values.size(); + + Entry search_entry(unique_cstr); + const_iterator pos, end = m_map.end(); + for (pos = std::lower_bound(m_map.begin(), end, search_entry); pos != end; + ++pos) { + if (pos->cstring == unique_cstr) + values.push_back(pos->value); + else + break; + } + + return values.size() - start_size; + } + + size_t GetValues(const RegularExpression ®ex, + std::vector &values) const { + const size_t start_size = values.size(); + + const_iterator pos, end = m_map.end(); + for (pos = m_map.begin(); pos != end; ++pos) { + if (regex.Execute(pos->cstring.GetCString())) + values.push_back(pos->value); + } + + return values.size() - start_size; + } + + //------------------------------------------------------------------ + // Get the total number of entries in this map. + //------------------------------------------------------------------ + size_t GetSize() const { return m_map.size(); } + + //------------------------------------------------------------------ + // Returns true if this map is empty. + //------------------------------------------------------------------ + bool IsEmpty() const { return m_map.empty(); } + + //------------------------------------------------------------------ + // Reserve memory for at least "n" entries in the map. This is + // useful to call when you know you will be adding a lot of entries + // using UniqueCStringMap::Append() (which should be followed by a + // call to UniqueCStringMap::Sort()) or to UniqueCStringMap::Insert(). + //------------------------------------------------------------------ + void Reserve(size_t n) { m_map.reserve(n); } + + //------------------------------------------------------------------ + // Sort the unsorted contents in this map. A typical code flow would + // be: + // size_t approximate_num_entries = .... + // UniqueCStringMap my_map; + // my_map.Reserve (approximate_num_entries); + // for (...) + // { + // my_map.Append (UniqueCStringMap::Entry(GetName(...), GetValue(...))); + // } + // my_map.Sort(); + //------------------------------------------------------------------ + void Sort() { std::sort(m_map.begin(), m_map.end()); } + + //------------------------------------------------------------------ + // Since we are using a vector to contain our items it will always + // double its memory consumption as things are added to the vector, + // so if you intend to keep a UniqueCStringMap around and have + // a lot of entries in the map, you will want to call this function + // to create a new vector and copy _only_ the exact size needed as + // part of the finalization of the string map. + //------------------------------------------------------------------ + void SizeToFit() { + if (m_map.size() < m_map.capacity()) { + collection temp(m_map.begin(), m_map.end()); + m_map.swap(temp); + } + } + + size_t Erase(ConstString unique_cstr) { + size_t num_removed = 0; + Entry search_entry(unique_cstr); + iterator end = m_map.end(); + iterator begin = m_map.begin(); + iterator lower_pos = std::lower_bound(begin, end, search_entry); + if (lower_pos != end) { + if (lower_pos->cstring == unique_cstr) { + iterator upper_pos = std::upper_bound(lower_pos, end, search_entry); + if (lower_pos == upper_pos) { + m_map.erase(lower_pos); + num_removed = 1; + } else { + num_removed = std::distance(lower_pos, upper_pos); + m_map.erase(lower_pos, upper_pos); + } + } + } + return num_removed; + } + +protected: + typedef std::vector collection; + typedef typename collection::iterator iterator; + typedef typename collection::const_iterator const_iterator; + collection m_map; +}; + +} // namespace lldb_private + +#endif // liblldb_UniqueCStringMap_h_ diff --git a/include/lldb/Core/UserSettingsController.h b/include/lldb/Core/UserSettingsController.h new file mode 100644 index 000000000..67bc9b2c0 --- /dev/null +++ b/include/lldb/Core/UserSettingsController.h @@ -0,0 +1,105 @@ +//====-- UserSettingsController.h --------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UserSettingsController_h_ +#define liblldb_UserSettingsController_h_ + +#include "lldb/Utility/Status.h" // for Status +#include "lldb/lldb-forward.h" // for OptionValuePropertiesSP +#include "lldb/lldb-private-enumerations.h" // for VarSetOperationType + +#include "llvm/ADT/StringRef.h" // for StringRef + +#include + +#include // for size_t +#include // for uint32_t + +namespace lldb_private { +class CommandInterpreter; +} +namespace lldb_private { +class ConstString; +} +namespace lldb_private { +class ExecutionContext; +} +namespace lldb_private { +class Property; +} +namespace lldb_private { +class Stream; +} + +namespace lldb_private { + +class Properties { +public: + Properties() : m_collection_sp() {} + + Properties(const lldb::OptionValuePropertiesSP &collection_sp) + : m_collection_sp(collection_sp) {} + + virtual ~Properties() {} + + virtual lldb::OptionValuePropertiesSP GetValueProperties() const { + // This function is virtual in case subclasses want to lazily + // implement creating the properties. + return m_collection_sp; + } + + virtual lldb::OptionValueSP GetPropertyValue(const ExecutionContext *exe_ctx, + llvm::StringRef property_path, + bool will_modify, + Status &error) const; + + virtual Status SetPropertyValue(const ExecutionContext *exe_ctx, + VarSetOperationType op, + llvm::StringRef property_path, + llvm::StringRef value); + + virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx, + Stream &strm, llvm::StringRef property_path, + uint32_t dump_mask); + + virtual void DumpAllPropertyValues(const ExecutionContext *exe_ctx, + Stream &strm, uint32_t dump_mask); + + virtual void DumpAllDescriptions(CommandInterpreter &interpreter, + Stream &strm) const; + + size_t Apropos(llvm::StringRef keyword, + std::vector &matching_properties) const; + + lldb::OptionValuePropertiesSP GetSubProperty(const ExecutionContext *exe_ctx, + const ConstString &name); + + // We sometimes need to introduce a setting to enable experimental features, + // but then we don't want the setting for these to cause errors when the + // setting + // goes away. Add a sub-topic of the settings using this experimental name, + // and + // two things will happen. One is that settings that don't find the name will + // not + // be treated as errors. Also, if you decide to keep the settings just move + // them into + // the containing properties, and we will auto-forward the experimental + // settings to the + // real one. + static const char *GetExperimentalSettingsName(); + + static bool IsSettingExperimental(llvm::StringRef setting); + +protected: + lldb::OptionValuePropertiesSP m_collection_sp; +}; + +} // namespace lldb_private + +#endif // liblldb_UserSettingsController_h_ diff --git a/include/lldb/Core/Value.h b/include/lldb/Core/Value.h new file mode 100644 index 000000000..678b56fc4 --- /dev/null +++ b/include/lldb/Core/Value.h @@ -0,0 +1,271 @@ +//===-- 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_ + +#include "lldb/Core/Scalar.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-enumerations.h" // for ByteOrder, ByteOrder::eB... +#include "lldb/lldb-private-enumerations.h" // for AddressType +#include "lldb/lldb-private-types.h" // for type128, RegisterInfo + +#include "llvm/ADT/APInt.h" // for APInt + +#include + +#include // for uint8_t, uint32_t, uint64_t +#include // for size_t, memcpy + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class ExecutionContext; +} +namespace lldb_private { +class Module; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class Type; +} +namespace lldb_private { +class Variable; +} + +namespace lldb_private { + +class Value { +public: + // Values Less than zero are an error, greater than or equal to zero + // returns what the Scalar result is. + enum ValueType { + // m_value contains... + // ============================ + eValueTypeScalar, // raw scalar value + eValueTypeVector, // byte array of m_vector.length with endianness of + // m_vector.byte_order + eValueTypeFileAddress, // file address value + eValueTypeLoadAddress, // load address value + eValueTypeHostAddress // host address value (for memory in the process that + // is using liblldb) + }; + + enum ContextType // Type that describes Value::m_context + { + // m_context contains... + // ==================== + eContextTypeInvalid, // undefined + eContextTypeRegisterInfo, // RegisterInfo * (can be a scalar or a vector + // register) + eContextTypeLLDBType, // lldb_private::Type * + eContextTypeVariable // lldb_private::Variable * + }; + + const static size_t kMaxByteSize = 32u; + + struct Vector { + // The byte array must be big enough to hold vector registers for any + // supported target. + uint8_t bytes[kMaxByteSize]; + size_t length; + lldb::ByteOrder byte_order; + + Vector() : length(0), byte_order(lldb::eByteOrderInvalid) {} + + Vector(const Vector &vector) { *this = vector; } + const Vector &operator=(const Vector &vector) { + SetBytes(vector.bytes, vector.length, vector.byte_order); + return *this; + } + + void Clear() { length = 0; } + + bool SetBytes(const void *bytes, size_t length, + lldb::ByteOrder byte_order) { + this->length = length; + this->byte_order = byte_order; + if (length) + ::memcpy(this->bytes, bytes, + length < kMaxByteSize ? length : kMaxByteSize); + return IsValid(); + } + + bool IsValid() const { + return (length > 0 && length < kMaxByteSize && + byte_order != lldb::eByteOrderInvalid); + } + // Casts a vector, if valid, to an unsigned int of matching or largest + // supported size. + // Truncates to the beginning of the vector if required. + // Returns a default constructed Scalar if the Vector data is internally + // inconsistent. + llvm::APInt rhs = llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, + ((type128 *)bytes)->x); + Scalar GetAsScalar() const { + Scalar scalar; + if (IsValid()) { + if (length == 1) + scalar = *(const uint8_t *)bytes; + else if (length == 2) + scalar = *(const uint16_t *)bytes; + else if (length == 4) + scalar = *(const uint32_t *)bytes; + else if (length == 8) + scalar = *(const uint64_t *)bytes; + else if (length >= 16) + scalar = rhs; + } + return scalar; + } + }; + + Value(); + Value(const Scalar &scalar); + Value(const Vector &vector); + Value(const void *bytes, int len); + Value(const Value &rhs); + + void SetBytes(const void *bytes, int len); + + void AppendBytes(const void *bytes, int len); + + Value &operator=(const Value &rhs); + + const CompilerType &GetCompilerType(); + + void SetCompilerType(const CompilerType &compiler_type); + + ValueType GetValueType() const; + + AddressType GetValueAddressType() const; + + ContextType GetContextType() const { return m_context_type; } + + void SetValueType(ValueType value_type) { m_value_type = value_type; } + + void ClearContext() { + m_context = nullptr; + m_context_type = eContextTypeInvalid; + } + + void SetContext(ContextType context_type, void *p) { + m_context_type = context_type; + m_context = p; + if (m_context_type == eContextTypeRegisterInfo) { + RegisterInfo *reg_info = GetRegisterInfo(); + if (reg_info->encoding == lldb::eEncodingVector && + m_vector.byte_order != lldb::eByteOrderInvalid) + SetValueType(eValueTypeScalar); + } + } + + RegisterInfo *GetRegisterInfo() const; + + Type *GetType(); + + Scalar &ResolveValue(ExecutionContext *exe_ctx); + + const Scalar &GetScalar() const { return m_value; } + + const Vector &GetVector() const { return m_vector; } + + Scalar &GetScalar() { return m_value; } + + Vector &GetVector() { return m_vector; } + + bool SetVectorBytes(const Vector &vector) { + m_vector = vector; + return m_vector.IsValid(); + } + + bool SetVectorBytes(uint8_t *bytes, size_t length, + lldb::ByteOrder byte_order) { + return m_vector.SetBytes(bytes, length, byte_order); + } + + bool SetScalarFromVector() { + if (m_vector.IsValid()) { + m_value = m_vector.GetAsScalar(); + return true; + } + return false; + } + + size_t ResizeData(size_t len); + + size_t AppendDataToHostBuffer(const Value &rhs); + + DataBufferHeap &GetBuffer() { return m_data_buffer; } + + const DataBufferHeap &GetBuffer() const { return m_data_buffer; } + + bool ValueOf(ExecutionContext *exe_ctx); + + Variable *GetVariable(); + + void Dump(Stream *strm); + + lldb::Format GetValueDefaultFormat(); + + uint64_t GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx); + + Status GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, + uint32_t data_offset, + Module *module); // Can be nullptr + + static const char *GetValueTypeAsCString(ValueType context_type); + + static const char *GetContextTypeAsCString(ContextType context_type); + + bool GetData(DataExtractor &data); + + void Clear(); + +protected: + Scalar m_value; + Vector m_vector; + CompilerType m_compiler_type; + void *m_context; + ValueType m_value_type; + ContextType m_context_type; + DataBufferHeap m_data_buffer; +}; + +class ValueList { +public: + ValueList() : m_values() {} + + ValueList(const ValueList &rhs); + + ~ValueList() = default; + + 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(); + +private: + typedef std::vector collection; + + collection m_values; +}; + +} // namespace lldb_private + +#endif // liblldb_Value_h_ diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h new file mode 100644 index 000000000..fa1d14870 --- /dev/null +++ b/include/lldb/Core/ValueObject.h @@ -0,0 +1,1087 @@ +//===-- 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_ + +#include "lldb/Core/Value.h" +#include "lldb/DataFormatters/DumpValueObjectOptions.h" // for DumpValueObj... +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/Type.h" // for TypeImpl +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/SharedCluster.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-defines.h" // for LLDB_INVALID... +#include "lldb/lldb-enumerations.h" // for DynamicValue... +#include "lldb/lldb-forward.h" // for ValueObjectSP +#include "lldb/lldb-private-enumerations.h" // for AddressType +#include "lldb/lldb-types.h" // for addr_t, offs... + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" // for StringRef + +#include +#include +#include +#include // for recursive_mutex +#include // for string +#include // for pair + +#include // for size_t +#include // for uint32_t +namespace lldb_private { +class Declaration; +} +namespace lldb_private { +class EvaluateExpressionOptions; +} +namespace lldb_private { +class ExecutionContextScope; +} +namespace lldb_private { +class Log; +} +namespace lldb_private { +class Scalar; +} +namespace lldb_private { +class Stream; +} +namespace lldb_private { +class SymbolContextScope; +} +namespace lldb_private { +class TypeFormatImpl; +} +namespace lldb_private { +class TypeSummaryImpl; +} +namespace lldb_private { +class TypeSummaryOptions; +} +namespace lldb_private { + +/// ValueObject: +/// +/// This abstract class provides an interface to a particular value, be it a +/// register, a local or global variable, +/// that is evaluated in some particular scope. The ValueObject also has the +/// capability of being the "child" of +/// some other variable object, and in turn of having children. +/// If a ValueObject is a root variable object - having no parent - then it must +/// be constructed with respect to some +/// particular ExecutionContextScope. If it is a child, it inherits the +/// ExecutionContextScope from its parent. +/// The ValueObject will update itself if necessary before fetching its value, +/// summary, object description, etc. +/// But it will always update itself in the ExecutionContextScope with which it +/// was originally created. + +/// A brief note on life cycle management for ValueObjects. This is a little +/// tricky because a ValueObject can contain +/// various other ValueObjects - the Dynamic Value, its children, the +/// dereference value, etc. Any one of these can be +/// handed out as a shared pointer, but for that contained value object to be +/// valid, the root object and potentially other +/// of the value objects need to stay around. +/// We solve this problem by handing out shared pointers to the Value Object and +/// any of its dependents using a shared +/// ClusterManager. This treats each shared pointer handed out for the entire +/// cluster as a reference to the whole +/// cluster. The whole cluster will stay around until the last reference is +/// released. +/// +/// The ValueObject mostly handle this automatically, if a value object is made +/// with a Parent ValueObject, then it adds +/// itself to the ClusterManager of the parent. + +/// It does mean that external to the ValueObjects we should only ever make +/// available ValueObjectSP's, never ValueObjects +/// or pointers to them. So all the "Root level" ValueObject derived +/// constructors should be private, and +/// should implement a Create function that new's up object and returns a Shared +/// Pointer that it gets from the GetSP() method. +/// +/// However, if you are making an derived ValueObject that will be contained in +/// a parent value object, you should just +/// hold onto a pointer to it internally, and by virtue of passing the parent +/// ValueObject into its constructor, it will +/// be added to the ClusterManager for the parent. Then if you ever hand out a +/// Shared Pointer to the contained ValueObject, +/// just do so by calling GetSP() on the contained object. + +class ValueObject : public UserID { +public: + enum GetExpressionPathFormat { + eGetExpressionPathFormatDereferencePointers = 1, + eGetExpressionPathFormatHonorPointers + }; + + enum ValueObjectRepresentationStyle { + eValueObjectRepresentationStyleValue = 1, + eValueObjectRepresentationStyleSummary, + eValueObjectRepresentationStyleLanguageSpecific, + eValueObjectRepresentationStyleLocation, + eValueObjectRepresentationStyleChildrenCount, + eValueObjectRepresentationStyleType, + eValueObjectRepresentationStyleName, + eValueObjectRepresentationStyleExpressionPath + }; + + enum ExpressionPathScanEndReason { + eExpressionPathScanEndReasonEndOfString = 1, // out of data to parse + eExpressionPathScanEndReasonNoSuchChild, // child element not found + eExpressionPathScanEndReasonNoSuchSyntheticChild, // (synthetic) child + // element not found + eExpressionPathScanEndReasonEmptyRangeNotAllowed, // [] only allowed for + // arrays + eExpressionPathScanEndReasonDotInsteadOfArrow, // . used when -> should be + // used + eExpressionPathScanEndReasonArrowInsteadOfDot, // -> used when . should be + // used + eExpressionPathScanEndReasonFragileIVarNotAllowed, // ObjC ivar expansion + // not allowed + eExpressionPathScanEndReasonRangeOperatorNotAllowed, // [] not allowed by + // options + eExpressionPathScanEndReasonRangeOperatorInvalid, // [] not valid on objects + // other than scalars, + // pointers or arrays + eExpressionPathScanEndReasonArrayRangeOperatorMet, // [] is good for arrays, + // but I cannot parse it + eExpressionPathScanEndReasonBitfieldRangeOperatorMet, // [] is good for + // bitfields, but I + // cannot parse after + // it + eExpressionPathScanEndReasonUnexpectedSymbol, // something is malformed in + // the expression + eExpressionPathScanEndReasonTakingAddressFailed, // impossible to apply & + // operator + eExpressionPathScanEndReasonDereferencingFailed, // impossible to apply * + // operator + eExpressionPathScanEndReasonRangeOperatorExpanded, // [] was expanded into a + // VOList + eExpressionPathScanEndReasonSyntheticValueMissing, // getting the synthetic + // children failed + eExpressionPathScanEndReasonUnknown = 0xFFFF + }; + + enum ExpressionPathEndResultType { + eExpressionPathEndResultTypePlain = 1, // anything but... + eExpressionPathEndResultTypeBitfield, // a bitfield + eExpressionPathEndResultTypeBoundedRange, // a range [low-high] + eExpressionPathEndResultTypeUnboundedRange, // a range [] + eExpressionPathEndResultTypeValueObjectList, // several items in a VOList + eExpressionPathEndResultTypeInvalid = 0xFFFF + }; + + enum ExpressionPathAftermath { + eExpressionPathAftermathNothing = 1, // just return it + eExpressionPathAftermathDereference, // dereference the target + eExpressionPathAftermathTakeAddress // take target's address + }; + + enum ClearUserVisibleDataItems { + eClearUserVisibleDataItemsNothing = 1u << 0, + eClearUserVisibleDataItemsValue = 1u << 1, + eClearUserVisibleDataItemsSummary = 1u << 2, + eClearUserVisibleDataItemsLocation = 1u << 3, + eClearUserVisibleDataItemsDescription = 1u << 4, + eClearUserVisibleDataItemsSyntheticChildren = 1u << 5, + eClearUserVisibleDataItemsValidator = 1u << 6, + eClearUserVisibleDataItemsAllStrings = + eClearUserVisibleDataItemsValue | eClearUserVisibleDataItemsSummary | + eClearUserVisibleDataItemsLocation | + eClearUserVisibleDataItemsDescription, + eClearUserVisibleDataItemsAll = 0xFFFF + }; + + struct GetValueForExpressionPathOptions { + enum class SyntheticChildrenTraversal { + None, + ToSynthetic, + FromSynthetic, + Both + }; + + bool m_check_dot_vs_arrow_syntax; + bool m_no_fragile_ivar; + bool m_allow_bitfields_syntax; + SyntheticChildrenTraversal m_synthetic_children_traversal; + + GetValueForExpressionPathOptions( + bool dot = false, bool no_ivar = false, bool bitfield = true, + SyntheticChildrenTraversal synth_traverse = + SyntheticChildrenTraversal::ToSynthetic) + : m_check_dot_vs_arrow_syntax(dot), m_no_fragile_ivar(no_ivar), + m_allow_bitfields_syntax(bitfield), + m_synthetic_children_traversal(synth_traverse) {} + + GetValueForExpressionPathOptions &DoCheckDotVsArrowSyntax() { + m_check_dot_vs_arrow_syntax = true; + return *this; + } + + GetValueForExpressionPathOptions &DontCheckDotVsArrowSyntax() { + m_check_dot_vs_arrow_syntax = false; + return *this; + } + + GetValueForExpressionPathOptions &DoAllowFragileIVar() { + m_no_fragile_ivar = false; + return *this; + } + + GetValueForExpressionPathOptions &DontAllowFragileIVar() { + m_no_fragile_ivar = true; + return *this; + } + + GetValueForExpressionPathOptions &DoAllowBitfieldSyntax() { + m_allow_bitfields_syntax = true; + return *this; + } + + GetValueForExpressionPathOptions &DontAllowBitfieldSyntax() { + m_allow_bitfields_syntax = false; + return *this; + } + + GetValueForExpressionPathOptions & + SetSyntheticChildrenTraversal(SyntheticChildrenTraversal traverse) { + m_synthetic_children_traversal = traverse; + return *this; + } + + static const GetValueForExpressionPathOptions DefaultOptions() { + static GetValueForExpressionPathOptions g_default_options; + + return g_default_options; + } + }; + + class EvaluationPoint { + public: + EvaluationPoint(); + + EvaluationPoint(ExecutionContextScope *exe_scope, + bool use_selected = false); + + EvaluationPoint(const EvaluationPoint &rhs); + + ~EvaluationPoint(); + + const ExecutionContextRef &GetExecutionContextRef() const { + return m_exe_ctx_ref; + } + + // Set the EvaluationPoint to the values in exe_scope, + // Return true if the Evaluation Point changed. + // Since the ExecutionContextScope is always going to be valid currently, + // the Updated Context will also always be valid. + + // bool + // SetContext (ExecutionContextScope *exe_scope); + + void SetIsConstant() { + SetUpdated(); + m_mod_id.SetInvalid(); + } + + bool IsConstant() const { return !m_mod_id.IsValid(); } + + ProcessModID GetModID() const { return m_mod_id; } + + void SetUpdateID(ProcessModID new_id) { m_mod_id = new_id; } + + void SetNeedsUpdate() { m_needs_update = true; } + + void SetUpdated(); + + bool NeedsUpdating(bool accept_invalid_exe_ctx) { + SyncWithProcessState(accept_invalid_exe_ctx); + return m_needs_update; + } + + bool IsValid() { + const bool accept_invalid_exe_ctx = false; + if (!m_mod_id.IsValid()) + return false; + else if (SyncWithProcessState(accept_invalid_exe_ctx)) { + if (!m_mod_id.IsValid()) + return false; + } + return true; + } + + void SetInvalid() { + // Use the stop id to mark us as invalid, leave the thread id and the + // stack id around for logging and + // history purposes. + m_mod_id.SetInvalid(); + + // Can't update an invalid state. + m_needs_update = false; + } + + private: + bool SyncWithProcessState(bool accept_invalid_exe_ctx); + + ProcessModID m_mod_id; // This is the stop id when this ValueObject was last + // evaluated. + ExecutionContextRef m_exe_ctx_ref; + bool m_needs_update; + }; + + virtual ~ValueObject(); + + const EvaluationPoint &GetUpdatePoint() const { return m_update_point; } + + EvaluationPoint &GetUpdatePoint() { return m_update_point; } + + const ExecutionContextRef &GetExecutionContextRef() const { + return m_update_point.GetExecutionContextRef(); + } + + lldb::TargetSP GetTargetSP() const { + return m_update_point.GetExecutionContextRef().GetTargetSP(); + } + + lldb::ProcessSP GetProcessSP() const { + return m_update_point.GetExecutionContextRef().GetProcessSP(); + } + + lldb::ThreadSP GetThreadSP() const { + return m_update_point.GetExecutionContextRef().GetThreadSP(); + } + + lldb::StackFrameSP GetFrameSP() const { + return m_update_point.GetExecutionContextRef().GetFrameSP(); + } + + void SetNeedsUpdate(); + + CompilerType GetCompilerType(); + + // this vends a TypeImpl that is useful at the SB API layer + virtual TypeImpl GetTypeImpl(); + + virtual bool CanProvideValue(); + + //------------------------------------------------------------------ + // Subclasses must implement the functions below. + //------------------------------------------------------------------ + virtual uint64_t GetByteSize() = 0; + + virtual lldb::ValueType GetValueType() const = 0; + + //------------------------------------------------------------------ + // Subclasses can implement the functions below. + //------------------------------------------------------------------ + virtual ConstString GetTypeName(); + + virtual ConstString GetDisplayTypeName(); + + virtual ConstString GetQualifiedTypeName(); + + virtual lldb::LanguageType GetObjectRuntimeLanguage(); + + virtual uint32_t + GetTypeInfo(CompilerType *pointee_or_element_compiler_type = nullptr); + + virtual bool IsPointerType(); + + virtual bool IsArrayType(); + + virtual bool IsScalarType(); + + virtual bool IsPointerOrReferenceType(); + + virtual bool IsPossibleDynamicType(); + + bool IsNilReference(); + + bool IsUninitializedReference(); + + virtual bool IsBaseClass() { return false; } + + bool IsBaseClass(uint32_t &depth); + + virtual bool IsDereferenceOfParent() { return false; } + + bool IsIntegerType(bool &is_signed); + + virtual bool GetBaseClassPath(Stream &s); + + virtual void GetExpressionPath( + Stream &s, bool qualify_cxx_base_classes, + GetExpressionPathFormat = eGetExpressionPathFormatDereferencePointers); + + lldb::ValueObjectSP GetValueForExpressionPath( + llvm::StringRef expression, + ExpressionPathScanEndReason *reason_to_stop = nullptr, + ExpressionPathEndResultType *final_value_type = nullptr, + const GetValueForExpressionPathOptions &options = + GetValueForExpressionPathOptions::DefaultOptions(), + ExpressionPathAftermath *final_task_on_target = nullptr); + + virtual bool IsInScope() { return true; } + + virtual lldb::offset_t GetByteOffset() { return 0; } + + virtual uint32_t GetBitfieldBitSize() { return 0; } + + virtual uint32_t GetBitfieldBitOffset() { return 0; } + + bool IsBitfield() { + return (GetBitfieldBitSize() != 0) || (GetBitfieldBitOffset() != 0); + } + + virtual bool IsArrayItemForPointer() { return m_is_array_item_for_pointer; } + + virtual const char *GetValueAsCString(); + + virtual bool GetValueAsCString(const lldb_private::TypeFormatImpl &format, + std::string &destination); + + bool GetValueAsCString(lldb::Format format, std::string &destination); + + virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, + bool *success = nullptr); + + virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + + virtual bool SetValueFromCString(const char *value_str, Status &error); + + // Return the module associated with this value object in case the + // value is from an executable file and might have its data in + // sections of the file. This can be used for variables. + virtual lldb::ModuleSP GetModule(); + + ValueObject *GetRoot(); + + // Given a ValueObject, loop over itself and its parent, and its parent's + // parent, .. + // until either the given callback returns false, or you end up at a null + // pointer + ValueObject *FollowParentChain(std::function); + + virtual bool GetDeclaration(Declaration &decl); + + //------------------------------------------------------------------ + // The functions below should NOT be modified by subclasses + //------------------------------------------------------------------ + const Status &GetError(); + + const ConstString &GetName() const; + + virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create); + + // this will always create the children if necessary + lldb::ValueObjectSP GetChildAtIndexPath(llvm::ArrayRef idxs, + size_t *index_of_error = nullptr); + + lldb::ValueObjectSP + GetChildAtIndexPath(llvm::ArrayRef> idxs, + size_t *index_of_error = nullptr); + + // this will always create the children if necessary + lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef names, + ConstString *name_of_error = nullptr); + + lldb::ValueObjectSP + GetChildAtNamePath(llvm::ArrayRef> names, + ConstString *name_of_error = nullptr); + + virtual lldb::ValueObjectSP GetChildMemberWithName(const ConstString &name, + bool can_create); + + virtual size_t GetIndexOfChildWithName(const ConstString &name); + + size_t GetNumChildren(uint32_t max = UINT32_MAX); + + const Value &GetValue() const; + + Value &GetValue(); + + virtual bool ResolveValue(Scalar &scalar); + + // return 'false' whenever you set the error, otherwise + // callers may assume true means everything is OK - this will + // break breakpoint conditions among potentially a few others + virtual bool IsLogicalTrue(Status &error); + + virtual const char *GetLocationAsCString(); + + const char * + GetSummaryAsCString(lldb::LanguageType lang = lldb::eLanguageTypeUnknown); + + bool + GetSummaryAsCString(TypeSummaryImpl *summary_ptr, std::string &destination, + lldb::LanguageType lang = lldb::eLanguageTypeUnknown); + + bool GetSummaryAsCString(std::string &destination, + const TypeSummaryOptions &options); + + bool GetSummaryAsCString(TypeSummaryImpl *summary_ptr, + std::string &destination, + const TypeSummaryOptions &options); + + std::pair GetValidationStatus(); + + const char *GetObjectDescription(); + + bool HasSpecialPrintableRepresentation( + ValueObjectRepresentationStyle val_obj_display, + lldb::Format custom_format); + + enum class PrintableRepresentationSpecialCases : bool { + eDisable = false, + eAllow = true + }; + + bool + DumpPrintableRepresentation(Stream &s, + ValueObjectRepresentationStyle val_obj_display = + eValueObjectRepresentationStyleSummary, + lldb::Format custom_format = lldb::eFormatInvalid, + PrintableRepresentationSpecialCases special = + PrintableRepresentationSpecialCases::eAllow, + bool do_dump_error = true); + bool GetValueIsValid() const; + + // If you call this on a newly created ValueObject, it will always return + // false. + bool GetValueDidChange(); + + bool UpdateValueIfNeeded(bool update_format = true); + + bool UpdateFormatsIfNeeded(); + + lldb::ValueObjectSP GetSP() { return m_manager->GetSharedPointer(this); } + + // Change the name of the current ValueObject. Should *not* be used from a + // synthetic child provider as it would change the name of the non synthetic + // child as well. + void SetName(const ConstString &name); + + virtual lldb::addr_t GetAddressOf(bool scalar_is_load_address = true, + AddressType *address_type = nullptr); + + lldb::addr_t GetPointerValue(AddressType *address_type = nullptr); + + lldb::ValueObjectSP GetSyntheticChild(const ConstString &key) const; + + lldb::ValueObjectSP GetSyntheticArrayMember(size_t index, bool can_create); + + lldb::ValueObjectSP GetSyntheticBitFieldChild(uint32_t from, uint32_t to, + bool can_create); + + lldb::ValueObjectSP GetSyntheticExpressionPathChild(const char *expression, + bool can_create); + + virtual lldb::ValueObjectSP + GetSyntheticChildAtOffset(uint32_t offset, const CompilerType &type, + bool can_create, + ConstString name_const_str = ConstString()); + + virtual lldb::ValueObjectSP + GetSyntheticBase(uint32_t offset, const CompilerType &type, bool can_create, + ConstString name_const_str = ConstString()); + + virtual lldb::ValueObjectSP GetDynamicValue(lldb::DynamicValueType valueType); + + lldb::DynamicValueType GetDynamicValueType(); + + virtual lldb::ValueObjectSP GetStaticValue(); + + virtual lldb::ValueObjectSP GetNonSyntheticValue(); + + lldb::ValueObjectSP GetSyntheticValue(bool use_synthetic = true); + + virtual bool HasSyntheticValue(); + + virtual bool IsSynthetic() { return false; } + + lldb::ValueObjectSP + GetQualifiedRepresentationIfAvailable(lldb::DynamicValueType dynValue, + bool synthValue); + + virtual lldb::ValueObjectSP CreateConstantValue(const ConstString &name); + + virtual lldb::ValueObjectSP Dereference(Status &error); + + // Creates a copy of the ValueObject with a new name and setting the current + // ValueObject as its parent. It should be used when we want to change the + // name of a ValueObject without modifying the actual ValueObject itself + // (e.g. sythetic child provider). + virtual lldb::ValueObjectSP Clone(const ConstString &new_name); + + virtual lldb::ValueObjectSP AddressOf(Status &error); + + virtual lldb::addr_t GetLiveAddress() { return LLDB_INVALID_ADDRESS; } + + virtual void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS, + AddressType address_type = eAddressTypeLoad) {} + + // Find the address of the C++ vtable pointer + virtual lldb::addr_t GetCPPVTableAddress(AddressType &address_type); + + virtual lldb::ValueObjectSP Cast(const CompilerType &compiler_type); + + virtual lldb::ValueObjectSP CastPointerType(const char *name, + CompilerType &ast_type); + + virtual lldb::ValueObjectSP CastPointerType(const char *name, + lldb::TypeSP &type_sp); + + // The backing bits of this value object were updated, clear any + // descriptive string, so we know we have to refetch them + virtual void ValueUpdated() { + ClearUserVisibleData(eClearUserVisibleDataItemsValue | + eClearUserVisibleDataItemsSummary | + eClearUserVisibleDataItemsDescription); + } + + virtual bool IsDynamic() { return false; } + + virtual bool DoesProvideSyntheticValue() { return false; } + + virtual bool IsSyntheticChildrenGenerated(); + + virtual void SetSyntheticChildrenGenerated(bool b); + + virtual SymbolContextScope *GetSymbolContextScope(); + + void Dump(Stream &s); + + void Dump(Stream &s, const DumpValueObjectOptions &options); + + static lldb::ValueObjectSP + CreateValueObjectFromExpression(llvm::StringRef name, + llvm::StringRef expression, + const ExecutionContext &exe_ctx); + + static lldb::ValueObjectSP + CreateValueObjectFromExpression(llvm::StringRef name, + llvm::StringRef expression, + const ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options); + + static lldb::ValueObjectSP + CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, + const ExecutionContext &exe_ctx, + CompilerType type); + + static lldb::ValueObjectSP + CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, + const ExecutionContext &exe_ctx, CompilerType type); + + void LogValueObject(Log *log); + + void LogValueObject(Log *log, const DumpValueObjectOptions &options); + + lldb::ValueObjectSP Persist(); + + // returns true if this is a char* or a char[] + // if it is a char* and check_pointer is true, + // it also checks that the pointer is valid + bool IsCStringContainer(bool check_pointer = false); + + std::pair + ReadPointedString(lldb::DataBufferSP &buffer_sp, Status &error, + uint32_t max_length = 0, bool honor_array = true, + lldb::Format item_format = lldb::eFormatCharArray); + + virtual size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0, + uint32_t item_count = 1); + + virtual uint64_t GetData(DataExtractor &data, Status &error); + + virtual bool SetData(DataExtractor &data, Status &error); + + virtual bool GetIsConstant() const { return m_update_point.IsConstant(); } + + bool NeedsUpdating() { + const bool accept_invalid_exe_ctx = + (CanUpdateWithInvalidExecutionContext() == eLazyBoolYes); + return m_update_point.NeedsUpdating(accept_invalid_exe_ctx); + } + + void SetIsConstant() { m_update_point.SetIsConstant(); } + + lldb::Format GetFormat() const; + + virtual void SetFormat(lldb::Format format) { + if (format != m_format) + ClearUserVisibleData(eClearUserVisibleDataItemsValue); + m_format = format; + } + + virtual lldb::LanguageType GetPreferredDisplayLanguage(); + + void SetPreferredDisplayLanguage(lldb::LanguageType); + + lldb::TypeSummaryImplSP GetSummaryFormat() { + UpdateFormatsIfNeeded(); + return m_type_summary_sp; + } + + void SetSummaryFormat(lldb::TypeSummaryImplSP format) { + m_type_summary_sp = format; + ClearUserVisibleData(eClearUserVisibleDataItemsSummary); + } + + lldb::TypeValidatorImplSP GetValidator() { + UpdateFormatsIfNeeded(); + return m_type_validator_sp; + } + + void SetValidator(lldb::TypeValidatorImplSP format) { + m_type_validator_sp = format; + ClearUserVisibleData(eClearUserVisibleDataItemsValidator); + } + + void SetValueFormat(lldb::TypeFormatImplSP format) { + m_type_format_sp = format; + ClearUserVisibleData(eClearUserVisibleDataItemsValue); + } + + lldb::TypeFormatImplSP GetValueFormat() { + UpdateFormatsIfNeeded(); + return m_type_format_sp; + } + + void SetSyntheticChildren(const lldb::SyntheticChildrenSP &synth_sp) { + if (synth_sp.get() == m_synthetic_children_sp.get()) + return; + ClearUserVisibleData(eClearUserVisibleDataItemsSyntheticChildren); + m_synthetic_children_sp = synth_sp; + } + + lldb::SyntheticChildrenSP GetSyntheticChildren() { + UpdateFormatsIfNeeded(); + return m_synthetic_children_sp; + } + + // Use GetParent for display purposes, but if you want to tell the parent to + // update itself + // then use m_parent. The ValueObjectDynamicValue's parent is not the correct + // parent for + // displaying, they are really siblings, so for display it needs to route + // through to its grandparent. + virtual ValueObject *GetParent() { return m_parent; } + + virtual const ValueObject *GetParent() const { return m_parent; } + + ValueObject *GetNonBaseClassParent(); + + void SetAddressTypeOfChildren(AddressType at) { + m_address_type_of_ptr_or_ref_children = at; + } + + AddressType GetAddressTypeOfChildren(); + + void SetHasCompleteType() { m_did_calculate_complete_objc_class_type = true; } + + //------------------------------------------------------------------ + /// Find out if a ValueObject might have children. + /// + /// This call is much more efficient than CalculateNumChildren() as + /// it doesn't need to complete the underlying type. This is designed + /// to be used in a UI environment in order to detect if the + /// disclosure triangle should be displayed or not. + /// + /// This function returns true for class, union, structure, + /// pointers, references, arrays and more. Again, it does so without + /// doing any expensive type completion. + /// + /// @return + /// Returns \b true if the ValueObject might have children, or \b + /// false otherwise. + //------------------------------------------------------------------ + virtual bool MightHaveChildren(); + + virtual lldb::VariableSP GetVariable() { return nullptr; } + + virtual bool IsRuntimeSupportValue(); + + virtual uint64_t GetLanguageFlags(); + + virtual void SetLanguageFlags(uint64_t flags); + +protected: + typedef ClusterManager ValueObjectManager; + + class ChildrenManager { + public: + ChildrenManager() : m_mutex(), m_children(), m_children_count(0) {} + + bool HasChildAtIndex(size_t idx) { + std::lock_guard guard(m_mutex); + return (m_children.find(idx) != m_children.end()); + } + + ValueObject *GetChildAtIndex(size_t idx) { + std::lock_guard guard(m_mutex); + const auto iter = m_children.find(idx); + return ((iter == m_children.end()) ? nullptr : iter->second); + } + + void SetChildAtIndex(size_t idx, ValueObject *valobj) { + // we do not need to be mutex-protected to make a pair + ChildrenPair pair(idx, valobj); + std::lock_guard guard(m_mutex); + m_children.insert(pair); + } + + void SetChildrenCount(size_t count) { Clear(count); } + + size_t GetChildrenCount() { return m_children_count; } + + void Clear(size_t new_count = 0) { + std::lock_guard guard(m_mutex); + m_children_count = new_count; + m_children.clear(); + } + + private: + typedef std::map ChildrenMap; + typedef ChildrenMap::iterator ChildrenIterator; + typedef ChildrenMap::value_type ChildrenPair; + std::recursive_mutex m_mutex; + ChildrenMap m_children; + size_t m_children_count; + }; + + //------------------------------------------------------------------ + // Classes that inherit from ValueObject can see and modify these + //------------------------------------------------------------------ + ValueObject + *m_parent; // The parent value object, or nullptr if this has no parent + ValueObject *m_root; // The root of the hierarchy for this ValueObject (or + // nullptr if never calculated) + EvaluationPoint m_update_point; // Stores both the stop id and the full + // context at which this value was last + // updated. When we are asked to update the value object, we check whether + // the context & stop id are the same before updating. + ConstString m_name; // The name of this object + DataExtractor + m_data; // A data extractor that can be used to extract the value. + Value m_value; + Status + m_error; // An error object that can describe any errors that occur when + // updating values. + std::string m_value_str; // Cached value string that will get cleared if/when + // the value is updated. + std::string m_old_value_str; // Cached old value string from the last time the + // value was gotten + std::string m_location_str; // Cached location string that will get cleared + // if/when the value is updated. + std::string m_summary_str; // Cached summary string that will get cleared + // if/when the value is updated. + std::string m_object_desc_str; // Cached result of the "object printer". This + // differs from the summary + // in that the summary is consed up by us, the object_desc_string is builtin. + + llvm::Optional> + m_validation_result; + + CompilerType m_override_type; // If the type of the value object should be + // overridden, the type to impose. + + ValueObjectManager *m_manager; // This object is managed by the root object + // (any ValueObject that gets created + // without a parent.) The manager gets passed through all the generations of + // dependent objects, and will keep the whole cluster of objects alive as long + // as a shared pointer to any of them has been handed out. Shared pointers to + // value objects must always be made with the GetSP method. + + ChildrenManager m_children; + std::map m_synthetic_children; + + ValueObject *m_dynamic_value; + ValueObject *m_synthetic_value; + ValueObject *m_deref_valobj; + + lldb::ValueObjectSP m_addr_of_valobj_sp; // We have to hold onto a shared + // pointer to this one because it is + // created + // as an independent ValueObjectConstResult, which isn't managed by us. + + lldb::Format m_format; + lldb::Format m_last_format; + uint32_t m_last_format_mgr_revision; + lldb::TypeSummaryImplSP m_type_summary_sp; + lldb::TypeFormatImplSP m_type_format_sp; + lldb::SyntheticChildrenSP m_synthetic_children_sp; + lldb::TypeValidatorImplSP m_type_validator_sp; + ProcessModID m_user_id_of_forced_summary; + AddressType m_address_type_of_ptr_or_ref_children; + + llvm::SmallVector m_value_checksum; + + lldb::LanguageType m_preferred_display_language; + + uint64_t m_language_flags; + + bool m_value_is_valid : 1, m_value_did_change : 1, m_children_count_valid : 1, + m_old_value_valid : 1, m_is_deref_of_parent : 1, + m_is_array_item_for_pointer : 1, m_is_bitfield_for_scalar : 1, + m_is_child_at_offset : 1, m_is_getting_summary : 1, + m_did_calculate_complete_objc_class_type : 1, + m_is_synthetic_children_generated : 1; + + friend class ValueObjectChild; + friend class ClangExpressionDeclMap; // For GetValue + friend class ExpressionVariable; // For SetName + friend class Target; // For SetName + friend class ValueObjectConstResultImpl; + friend class ValueObjectSynthetic; // For ClearUserVisibleData + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + + // Use the no-argument constructor to make a constant variable object (with no + // ExecutionContextScope.) + + ValueObject(); + + // Use this constructor to create a "root variable object". The ValueObject + // will be locked to this context + // through-out its lifespan. + + ValueObject(ExecutionContextScope *exe_scope, + AddressType child_ptr_or_ref_addr_type = eAddressTypeLoad); + + // Use this constructor to create a ValueObject owned by another ValueObject. + // It will inherit the ExecutionContext + // of its parent. + + ValueObject(ValueObject &parent); + + ValueObjectManager *GetManager() { return m_manager; } + + virtual bool UpdateValue() = 0; + + virtual LazyBool CanUpdateWithInvalidExecutionContext() { + return eLazyBoolCalculate; + } + + virtual void CalculateDynamicValue(lldb::DynamicValueType use_dynamic); + + virtual lldb::DynamicValueType GetDynamicValueTypeImpl() { + return lldb::eNoDynamicValues; + } + + virtual bool HasDynamicValueTypeInfo() { return false; } + + virtual void CalculateSyntheticValue(bool use_synthetic = true); + + // Should only be called by ValueObject::GetChildAtIndex() + // Returns a ValueObject managed by this ValueObject's manager. + virtual ValueObject *CreateChildAtIndex(size_t idx, + bool synthetic_array_member, + int32_t synthetic_index); + + // Should only be called by ValueObject::GetNumChildren() + virtual size_t CalculateNumChildren(uint32_t max = UINT32_MAX) = 0; + + void SetNumChildren(size_t num_children); + + void SetValueDidChange(bool value_changed); + + void SetValueIsValid(bool valid); + + void ClearUserVisibleData( + uint32_t items = ValueObject::eClearUserVisibleDataItemsAllStrings); + + void AddSyntheticChild(const ConstString &key, ValueObject *valobj); + + DataExtractor &GetDataExtractor(); + + void ClearDynamicTypeInformation(); + + //------------------------------------------------------------------ + // Subclasses must implement the functions below. + //------------------------------------------------------------------ + + virtual CompilerType GetCompilerTypeImpl() = 0; + + const char *GetLocationAsCStringImpl(const Value &value, + const DataExtractor &data); + + bool IsChecksumEmpty(); + + void SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType); + +private: + virtual CompilerType MaybeCalculateCompleteType(); + + lldb::ValueObjectSP GetValueForExpressionPath_Impl( + llvm::StringRef expression_cstr, + ExpressionPathScanEndReason *reason_to_stop, + ExpressionPathEndResultType *final_value_type, + const GetValueForExpressionPathOptions &options, + ExpressionPathAftermath *final_task_on_target); + + DISALLOW_COPY_AND_ASSIGN(ValueObject); +}; + +//------------------------------------------------------------------------------ +// A value object manager class that is seeded with the static variable value +// and it vends the user facing value object. If the type is dynamic it can +// vend the dynamic type. If this user type also has a synthetic type associated +// with it, it will vend the synthetic type. The class watches the process' stop +// ID and will update the user type when needed. +//------------------------------------------------------------------------------ +class ValueObjectManager { + // The root value object is the static typed variable object. + lldb::ValueObjectSP m_root_valobj_sp; + // The user value object is the value object the user wants to see. + lldb::ValueObjectSP m_user_valobj_sp; + lldb::DynamicValueType m_use_dynamic; + uint32_t m_stop_id; // The stop ID that m_user_valobj_sp is valid for. + bool m_use_synthetic; + +public: + ValueObjectManager() {} + + ValueObjectManager(lldb::ValueObjectSP in_valobj_sp, + lldb::DynamicValueType use_dynamic, bool use_synthetic); + + bool IsValid() const; + + lldb::ValueObjectSP GetRootSP() const { return m_root_valobj_sp; } + + // Gets the correct value object from the root object for a given process + // stop ID. If dynamic values are enabled, or if synthetic children are + // enabled, the value object that the user wants to see might change while + // debugging. + lldb::ValueObjectSP GetSP(); + + void SetUseDynamic(lldb::DynamicValueType use_dynamic); + void SetUseSynthetic(bool use_synthetic); + lldb::DynamicValueType GetUseDynamic() const { return m_use_dynamic; } + bool GetUseSynthetic() const { return m_use_synthetic; } + lldb::TargetSP GetTargetSP() const; + lldb::ProcessSP GetProcessSP() const; + lldb::ThreadSP GetThreadSP() const; + lldb::StackFrameSP GetFrameSP() const; +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObject_h_ diff --git a/include/lldb/Core/ValueObjectCast.h b/include/lldb/Core/ValueObjectCast.h new file mode 100644 index 000000000..aaa1ecb67 --- /dev/null +++ b/include/lldb/Core/ValueObjectCast.h @@ -0,0 +1,71 @@ +//===-- ValueObjectDynamicValue.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectCast_h_ +#define liblldb_ValueObjectCast_h_ + +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ValueType +#include "lldb/lldb-forward.h" // for ValueObjectSP + +#include // for size_t +#include // for uint32_t, uint64_t + +namespace lldb_private { +class ConstString; +} + +namespace lldb_private { + +//--------------------------------------------------------------------------------- +// A ValueObject that represents a given value represented as a different type. +//--------------------------------------------------------------------------------- +class ValueObjectCast : public ValueObject { +public: + ~ValueObjectCast() override; + + static lldb::ValueObjectSP Create(ValueObject &parent, + const ConstString &name, + const CompilerType &cast_type); + + uint64_t GetByteSize() override; + + size_t CalculateNumChildren(uint32_t max) override; + + lldb::ValueType GetValueType() const override; + + bool IsInScope() override; + + ValueObject *GetParent() override { + return ((m_parent != nullptr) ? m_parent->GetParent() : nullptr); + } + + const ValueObject *GetParent() const override { + return ((m_parent != nullptr) ? m_parent->GetParent() : nullptr); + } + +protected: + ValueObjectCast(ValueObject &parent, const ConstString &name, + const CompilerType &cast_type); + + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + CompilerType m_cast_type; + +private: + DISALLOW_COPY_AND_ASSIGN(ValueObjectCast); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectCast_h_ diff --git a/include/lldb/Core/ValueObjectChild.h b/include/lldb/Core/ValueObjectChild.h new file mode 100644 index 000000000..ec8c9e805 --- /dev/null +++ b/include/lldb/Core/ValueObjectChild.h @@ -0,0 +1,99 @@ +//===-- 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_ + +#include "lldb/Core/ValueObject.h" + +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ValueType +#include "lldb/lldb-private-enumerations.h" // for LazyBool, AddressType +#include "lldb/lldb-types.h" // for offset_t + +#include "llvm/ADT/Optional.h" + +#include // for size_t +#include // for uint32_t, uint64_t, int32_t + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A child of another ValueObject. +//---------------------------------------------------------------------- +class ValueObjectChild : public ValueObject { +public: + ~ValueObjectChild() override; + + uint64_t GetByteSize() override { return m_byte_size; } + + lldb::offset_t GetByteOffset() override { return m_byte_offset; } + + uint32_t GetBitfieldBitSize() override { return m_bitfield_bit_size; } + + uint32_t GetBitfieldBitOffset() override { return m_bitfield_bit_offset; } + + lldb::ValueType GetValueType() const override; + + size_t CalculateNumChildren(uint32_t max) override; + + ConstString GetTypeName() override; + + ConstString GetQualifiedTypeName() override; + + ConstString GetDisplayTypeName() override; + + bool IsInScope() override; + + bool IsBaseClass() override { return m_is_base_class; } + + bool IsDereferenceOfParent() override { return m_is_deref_of_parent; } + +protected: + bool UpdateValue() override; + + LazyBool CanUpdateWithInvalidExecutionContext() override; + + CompilerType GetCompilerTypeImpl() override { return m_compiler_type; } + + CompilerType m_compiler_type; + ConstString m_type_name; + uint64_t m_byte_size; + int32_t m_byte_offset; + uint8_t m_bitfield_bit_size; + uint8_t m_bitfield_bit_offset; + bool m_is_base_class; + bool m_is_deref_of_parent; + llvm::Optional m_can_update_with_invalid_exe_ctx; + + // + // void + // ReadValueFromMemory (ValueObject* parent, lldb::addr_t address); + +protected: + friend class ValueObject; + friend class ValueObjectConstResult; + friend class ValueObjectConstResultImpl; + + ValueObjectChild(ValueObject &parent, const CompilerType &compiler_type, + const ConstString &name, uint64_t byte_size, + int32_t byte_offset, uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, bool is_base_class, + bool is_deref_of_parent, + AddressType child_ptr_or_ref_addr_type, + uint64_t language_flags); + + DISALLOW_COPY_AND_ASSIGN(ValueObjectChild); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectChild_h_ diff --git a/include/lldb/Core/ValueObjectConstResult.h b/include/lldb/Core/ValueObjectConstResult.h new file mode 100644 index 000000000..1f56129df --- /dev/null +++ b/include/lldb/Core/ValueObjectConstResult.h @@ -0,0 +1,163 @@ +//===-- ValueObjectConstResult.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectConstResult_h_ +#define liblldb_ValueObjectConstResult_h_ + +#include "lldb/Core/Value.h" // for Value +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResultImpl.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/Status.h" // for Status +#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS +#include "lldb/lldb-enumerations.h" // for ByteOrder, Dynamic... +#include "lldb/lldb-forward.h" // for ValueObjectSP, Dat... +#include "lldb/lldb-private-enumerations.h" // for AddressType, Addre... +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t +#include // for uint32_t, uint64_t + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class ExecutionContextScope; +} +namespace lldb_private { +class Module; +} +namespace lldb_private { + +//---------------------------------------------------------------------- +// A frozen ValueObject copied into host memory +//---------------------------------------------------------------------- +class ValueObjectConstResult : public ValueObject { +public: + ~ValueObjectConstResult() override; + + static lldb::ValueObjectSP + Create(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, + uint32_t addr_byte_size, lldb::addr_t address = LLDB_INVALID_ADDRESS); + + static lldb::ValueObjectSP + Create(ExecutionContextScope *exe_scope, const CompilerType &compiler_type, + const ConstString &name, const DataExtractor &data, + lldb::addr_t address = LLDB_INVALID_ADDRESS); + + static lldb::ValueObjectSP + Create(ExecutionContextScope *exe_scope, const CompilerType &compiler_type, + const ConstString &name, const lldb::DataBufferSP &result_data_sp, + lldb::ByteOrder byte_order, uint32_t addr_size, + lldb::addr_t address = LLDB_INVALID_ADDRESS); + + static lldb::ValueObjectSP + Create(ExecutionContextScope *exe_scope, const CompilerType &compiler_type, + const ConstString &name, lldb::addr_t address, + AddressType address_type, uint32_t addr_byte_size); + + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + Value &value, const ConstString &name, + Module *module = nullptr); + + // When an expression fails to evaluate, we return an error + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + const Status &error); + + uint64_t GetByteSize() override; + + lldb::ValueType GetValueType() const override; + + size_t CalculateNumChildren(uint32_t max) override; + + ConstString GetTypeName() override; + + ConstString GetDisplayTypeName() override; + + bool IsInScope() override; + + void SetByteSize(size_t size); + + lldb::ValueObjectSP Dereference(Status &error) override; + + ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, + int32_t synthetic_index) override; + + lldb::ValueObjectSP GetSyntheticChildAtOffset( + uint32_t offset, const CompilerType &type, bool can_create, + ConstString name_const_str = ConstString()) override; + + lldb::ValueObjectSP AddressOf(Status &error) override; + + lldb::addr_t GetAddressOf(bool scalar_is_load_address = true, + AddressType *address_type = nullptr) override; + + size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0, + uint32_t item_count = 1) override; + + lldb::addr_t GetLiveAddress() override { return m_impl.GetLiveAddress(); } + + void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS, + AddressType address_type = eAddressTypeLoad) override { + m_impl.SetLiveAddress(addr, address_type); + } + + lldb::ValueObjectSP + GetDynamicValue(lldb::DynamicValueType valueType) override; + + lldb::LanguageType GetPreferredDisplayLanguage() override; + + lldb::ValueObjectSP Cast(const CompilerType &compiler_type) override; + +protected: + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + ConstString m_type_name; + uint64_t m_byte_size; + + ValueObjectConstResultImpl m_impl; + +private: + friend class ValueObjectConstResultImpl; + + ValueObjectConstResult(ExecutionContextScope *exe_scope, + lldb::ByteOrder byte_order, uint32_t addr_byte_size, + lldb::addr_t address); + + ValueObjectConstResult(ExecutionContextScope *exe_scope, + const CompilerType &compiler_type, + const ConstString &name, const DataExtractor &data, + lldb::addr_t address); + + ValueObjectConstResult(ExecutionContextScope *exe_scope, + const CompilerType &compiler_type, + const ConstString &name, + const lldb::DataBufferSP &result_data_sp, + lldb::ByteOrder byte_order, uint32_t addr_size, + lldb::addr_t address); + + ValueObjectConstResult(ExecutionContextScope *exe_scope, + const CompilerType &compiler_type, + const ConstString &name, lldb::addr_t address, + AddressType address_type, uint32_t addr_byte_size); + + ValueObjectConstResult(ExecutionContextScope *exe_scope, const Value &value, + const ConstString &name, Module *module = nullptr); + + ValueObjectConstResult(ExecutionContextScope *exe_scope, const Status &error); + + DISALLOW_COPY_AND_ASSIGN(ValueObjectConstResult); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectConstResult_h_ diff --git a/include/lldb/Core/ValueObjectConstResultCast.h b/include/lldb/Core/ValueObjectConstResultCast.h new file mode 100644 index 000000000..442cce420 --- /dev/null +++ b/include/lldb/Core/ValueObjectConstResultCast.h @@ -0,0 +1,77 @@ +//===-- ValueObjectConstResultCast.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectConstResultCast_h_ +#define liblldb_ValueObjectConstResultCast_h_ + +#include "lldb/Core/ValueObjectCast.h" +#include "lldb/Core/ValueObjectConstResultImpl.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_... +#include "lldb/lldb-forward.h" // for ValueObjectSP +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t +#include // for uint32_t, int32_t + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class ValueObject; +} + +namespace lldb_private { + +class ValueObjectConstResultCast : public ValueObjectCast { +public: + ValueObjectConstResultCast(ValueObject &parent, const ConstString &name, + const CompilerType &cast_type, + lldb::addr_t live_address = LLDB_INVALID_ADDRESS); + + ~ValueObjectConstResultCast() override; + + lldb::ValueObjectSP Dereference(Status &error) override; + + ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, + int32_t synthetic_index) override; + + virtual CompilerType GetCompilerType() { + return ValueObjectCast::GetCompilerType(); + } + + lldb::ValueObjectSP GetSyntheticChildAtOffset( + uint32_t offset, const CompilerType &type, bool can_create, + ConstString name_const_str = ConstString()) override; + + lldb::ValueObjectSP AddressOf(Status &error) override; + + size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0, + uint32_t item_count = 1) override; + + lldb::ValueObjectSP Cast(const CompilerType &compiler_type) override; + +protected: + ValueObjectConstResultImpl m_impl; + +private: + friend class ValueObject; + friend class ValueObjectConstResult; + friend class ValueObjectConstResultImpl; + + DISALLOW_COPY_AND_ASSIGN(ValueObjectConstResultCast); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectConstResultCast_h_ diff --git a/include/lldb/Core/ValueObjectConstResultChild.h b/include/lldb/Core/ValueObjectConstResultChild.h new file mode 100644 index 000000000..a74da0013 --- /dev/null +++ b/include/lldb/Core/ValueObjectConstResultChild.h @@ -0,0 +1,84 @@ +//===-- ValueObjectConstResultChild.h ----------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectConstResultChild_h_ +#define liblldb_ValueObjectConstResultChild_h_ + +#include "lldb/Core/ValueObjectChild.h" +#include "lldb/Core/ValueObjectConstResultImpl.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_... +#include "lldb/lldb-forward.h" // for ValueObjectSP +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t +#include // for uint32_t, int32_t +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class ValueObject; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A child of a ValueObjectConstResult. +//---------------------------------------------------------------------- +class ValueObjectConstResultChild : public ValueObjectChild { +public: + ValueObjectConstResultChild(ValueObject &parent, + const CompilerType &compiler_type, + const ConstString &name, uint32_t byte_size, + int32_t byte_offset, uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, bool is_base_class, + bool is_deref_of_parent, + lldb::addr_t live_address, + uint64_t language_flags); + + ~ValueObjectConstResultChild() override; + + lldb::ValueObjectSP Dereference(Status &error) override; + + ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, + int32_t synthetic_index) override; + + virtual CompilerType GetCompilerType() { + return ValueObjectChild::GetCompilerType(); + } + + lldb::ValueObjectSP GetSyntheticChildAtOffset( + uint32_t offset, const CompilerType &type, bool can_create, + ConstString name_const_str = ConstString()) override; + + lldb::ValueObjectSP AddressOf(Status &error) override; + + size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0, + uint32_t item_count = 1) override; + + lldb::ValueObjectSP Cast(const CompilerType &compiler_type) override; + +protected: + ValueObjectConstResultImpl m_impl; + +private: + friend class ValueObject; + friend class ValueObjectConstResult; + friend class ValueObjectConstResultImpl; + + DISALLOW_COPY_AND_ASSIGN(ValueObjectConstResultChild); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectConstResultChild_h_ diff --git a/include/lldb/Core/ValueObjectConstResultImpl.h b/include/lldb/Core/ValueObjectConstResultImpl.h new file mode 100644 index 000000000..d86f25e30 --- /dev/null +++ b/include/lldb/Core/ValueObjectConstResultImpl.h @@ -0,0 +1,88 @@ +//===-- ValueObjectConstResultImpl.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectConstResultImpl_h_ +#define liblldb_ValueObjectConstResultImpl_h_ + +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for LLDB_INVALID_ADDRESS +#include "lldb/lldb-forward.h" // for ValueObjectSP +#include "lldb/lldb-private-enumerations.h" // for AddressType, AddressType... +#include "lldb/lldb-types.h" // for addr_t + +#include // for size_t +#include // for uint32_t, int32_t +namespace lldb_private { +class CompilerType; +} +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class ValueObject; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A class wrapping common implementation details for operations in +// ValueObjectConstResult ( & Child ) that may need to jump from the host +// memory space into the target's memory space +//---------------------------------------------------------------------- +class ValueObjectConstResultImpl { +public: + ValueObjectConstResultImpl(ValueObject *valobj, + lldb::addr_t live_address = LLDB_INVALID_ADDRESS); + + virtual ~ValueObjectConstResultImpl() = default; + + lldb::ValueObjectSP Dereference(Status &error); + + ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, + int32_t synthetic_index); + + lldb::ValueObjectSP + GetSyntheticChildAtOffset(uint32_t offset, const CompilerType &type, + bool can_create, + ConstString name_const_str = ConstString()); + + lldb::ValueObjectSP AddressOf(Status &error); + + lldb::addr_t GetLiveAddress() { return m_live_address; } + + lldb::ValueObjectSP Cast(const CompilerType &compiler_type); + + void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS, + AddressType address_type = eAddressTypeLoad) { + m_live_address = addr; + m_live_address_type = address_type; + } + + virtual lldb::addr_t GetAddressOf(bool scalar_is_load_address = true, + AddressType *address_type = nullptr); + + virtual size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0, + uint32_t item_count = 1); + +private: + ValueObject *m_impl_backend; + lldb::addr_t m_live_address; + AddressType m_live_address_type; + lldb::ValueObjectSP m_load_addr_backend; + lldb::ValueObjectSP m_address_of_backend; + + DISALLOW_COPY_AND_ASSIGN(ValueObjectConstResultImpl); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectConstResultImpl_h_ diff --git a/include/lldb/Core/ValueObjectDynamicValue.h b/include/lldb/Core/ValueObjectDynamicValue.h new file mode 100644 index 000000000..018ee2c76 --- /dev/null +++ b/include/lldb/Core/ValueObjectDynamicValue.h @@ -0,0 +1,145 @@ +//===-- ValueObjectDynamicValue.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectDynamicValue_h_ +#define liblldb_ValueObjectDynamicValue_h_ + +#include "lldb/Core/Address.h" // for Address +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Symbol/Type.h" +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/Utility/SharingPtr.h" // for operator== +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for DynamicValueType, Langua... +#include "lldb/lldb-forward.h" // for ValueObjectSP, VariableSP +#include "lldb/lldb-private-enumerations.h" // for LazyBool, LazyBool::eLaz... + +#include // for assert +#include // for size_t +#include // for uint64_t, uint32_t + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Declaration; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { + +//---------------------------------------------------------------------- +// A ValueObject that represents memory at a given address, viewed as some +// set lldb type. +//---------------------------------------------------------------------- +class ValueObjectDynamicValue : public ValueObject { +public: + ~ValueObjectDynamicValue() override; + + uint64_t GetByteSize() override; + + ConstString GetTypeName() override; + + ConstString GetQualifiedTypeName() override; + + ConstString GetDisplayTypeName() override; + + size_t CalculateNumChildren(uint32_t max) override; + + lldb::ValueType GetValueType() const override; + + bool IsInScope() override; + + bool IsDynamic() override { return true; } + + bool IsBaseClass() override { + if (m_parent) + return m_parent->IsBaseClass(); + return false; + } + + bool GetIsConstant() const override { return false; } + + ValueObject *GetParent() override { + return ((m_parent != nullptr) ? m_parent->GetParent() : nullptr); + } + + const ValueObject *GetParent() const override { + return ((m_parent != nullptr) ? m_parent->GetParent() : nullptr); + } + + lldb::ValueObjectSP GetStaticValue() override { return m_parent->GetSP(); } + + void SetOwningSP(lldb::ValueObjectSP &owning_sp) { + if (m_owning_valobj_sp == owning_sp) + return; + + assert(m_owning_valobj_sp.get() == nullptr); + m_owning_valobj_sp = owning_sp; + } + + bool SetValueFromCString(const char *value_str, Status &error) override; + + bool SetData(DataExtractor &data, Status &error) override; + + TypeImpl GetTypeImpl() override; + + lldb::VariableSP GetVariable() override { + return m_parent ? m_parent->GetVariable() : nullptr; + } + + lldb::LanguageType GetPreferredDisplayLanguage() override; + + void SetPreferredDisplayLanguage(lldb::LanguageType); + + bool IsSyntheticChildrenGenerated() override; + + void SetSyntheticChildrenGenerated(bool b) override; + + bool GetDeclaration(Declaration &decl) override; + + uint64_t GetLanguageFlags() override; + + void SetLanguageFlags(uint64_t flags) override; + +protected: + bool UpdateValue() override; + + LazyBool CanUpdateWithInvalidExecutionContext() override { + return eLazyBoolYes; + } + + lldb::DynamicValueType GetDynamicValueTypeImpl() override { + return m_use_dynamic; + } + + bool HasDynamicValueTypeInfo() override { return true; } + + CompilerType GetCompilerTypeImpl() override; + + Address m_address; ///< The variable that this value object is based upon + TypeAndOrName m_dynamic_type_info; // We can have a type_sp or just a name + lldb::ValueObjectSP m_owning_valobj_sp; + lldb::DynamicValueType m_use_dynamic; + TypeImpl m_type_impl; + +private: + friend class ValueObject; + friend class ValueObjectConstResult; + ValueObjectDynamicValue(ValueObject &parent, + lldb::DynamicValueType use_dynamic); + + DISALLOW_COPY_AND_ASSIGN(ValueObjectDynamicValue); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectDynamicValue_h_ diff --git a/include/lldb/Core/ValueObjectList.h b/include/lldb/Core/ValueObjectList.h new file mode 100644 index 000000000..a0d2e681d --- /dev/null +++ b/include/lldb/Core/ValueObjectList.h @@ -0,0 +1,79 @@ +//===-- 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_ + +#include "lldb/lldb-forward.h" // for ValueObjectSP +#include "lldb/lldb-types.h" // for user_id_t + +#include + +#include // for size_t + +namespace lldb_private { +class ValueObject; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A collection of ValueObject values that +//---------------------------------------------------------------------- +class ValueObjectList { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + ValueObjectList(); + + ValueObjectList(const ValueObjectList &rhs); + + ~ValueObjectList(); + + const ValueObjectList &operator=(const ValueObjectList &rhs); + + void Append(const lldb::ValueObjectSP &val_obj_sp); + + void Append(const ValueObjectList &valobj_list); + + lldb::ValueObjectSP FindValueObjectByPointer(ValueObject *valobj); + + size_t GetSize() const; + + void Resize(size_t size); + + lldb::ValueObjectSP GetValueObjectAtIndex(size_t idx); + + lldb::ValueObjectSP RemoveValueObjectAtIndex(size_t idx); + + void SetValueObjectAtIndex(size_t idx, const lldb::ValueObjectSP &valobj_sp); + + lldb::ValueObjectSP FindValueObjectByValueName(const char *name); + + lldb::ValueObjectSP FindValueObjectByUID(lldb::user_id_t uid); + + void Swap(ValueObjectList &value_object_list); + + void Clear() { m_value_objects.clear(); } + + const std::vector &GetObjects() const { + return m_value_objects; + } +protected: + typedef std::vector collection; + //------------------------------------------------------------------ + // Classes that inherit from ValueObjectList can see and modify these + //------------------------------------------------------------------ + collection m_value_objects; +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectList_h_ diff --git a/include/lldb/Core/ValueObjectMemory.h b/include/lldb/Core/ValueObjectMemory.h new file mode 100644 index 000000000..8bb649cc3 --- /dev/null +++ b/include/lldb/Core/ValueObjectMemory.h @@ -0,0 +1,86 @@ +//===-- ValueObjectMemory.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectMemory_h_ +#define liblldb_ValueObjectMemory_h_ + +#include "lldb/Core/Address.h" // for Address +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ValueType +#include "lldb/lldb-forward.h" // for TypeSP, ValueObjectSP, ModuleSP +#include "llvm/ADT/StringRef.h" // for StringRef + +#include // for size_t +#include // for uint32_t, uint64_t + +namespace lldb_private { +class ExecutionContextScope; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A ValueObject that represents memory at a given address, viewed as some +// set lldb type. +//---------------------------------------------------------------------- +class ValueObjectMemory : public ValueObject { +public: + ~ValueObjectMemory() override; + + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + llvm::StringRef name, + const Address &address, + lldb::TypeSP &type_sp); + + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + llvm::StringRef name, + const Address &address, + const CompilerType &ast_type); + + uint64_t GetByteSize() override; + + ConstString GetTypeName() override; + + ConstString GetDisplayTypeName() override; + + size_t CalculateNumChildren(uint32_t max) override; + + lldb::ValueType GetValueType() const override; + + bool IsInScope() override; + + lldb::ModuleSP GetModule() override; + +protected: + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + Address m_address; ///< The variable that this value object is based upon + lldb::TypeSP m_type_sp; + CompilerType m_compiler_type; + +private: + ValueObjectMemory(ExecutionContextScope *exe_scope, llvm::StringRef name, + const Address &address, lldb::TypeSP &type_sp); + + ValueObjectMemory(ExecutionContextScope *exe_scope, llvm::StringRef name, + const Address &address, const CompilerType &ast_type); + //------------------------------------------------------------------ + // For ValueObject only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ValueObjectMemory); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectMemory_h_ diff --git a/include/lldb/Core/ValueObjectRegister.h b/include/lldb/Core/ValueObjectRegister.h new file mode 100644 index 000000000..2aaef9bee --- /dev/null +++ b/include/lldb/Core/ValueObjectRegister.h @@ -0,0 +1,191 @@ +//===-- 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_ + +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ValueType, ValueType::eValueTy... +#include "lldb/lldb-forward.h" // for RegisterContextSP, ValueObjectSP +#include "lldb/lldb-private-types.h" // for RegisterInfo, RegisterSet (ptr... + +#include // for size_t +#include // for uint32_t, uint64_t, int32_t + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class ExecutionContextScope; +} +namespace lldb_private { +class Scalar; +} +namespace lldb_private { +class Stream; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A ValueObject that contains a root variable that may or may not +// have children. +//---------------------------------------------------------------------- +class ValueObjectRegisterContext : public ValueObject { +public: + ~ValueObjectRegisterContext() override; + + uint64_t GetByteSize() override; + + lldb::ValueType GetValueType() const override { + return lldb::eValueTypeRegisterSet; + } + + ConstString GetTypeName() override; + + ConstString GetQualifiedTypeName() override; + + ConstString GetDisplayTypeName() override; + + size_t CalculateNumChildren(uint32_t max) override; + + ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, + int32_t synthetic_index) override; + +protected: + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + lldb::RegisterContextSP m_reg_ctx_sp; + +private: + ValueObjectRegisterContext(ValueObject &parent, + lldb::RegisterContextSP ®_ctx_sp); + //------------------------------------------------------------------ + // For ValueObject only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ValueObjectRegisterContext); +}; + +class ValueObjectRegisterSet : public ValueObject { +public: + ~ValueObjectRegisterSet() override; + + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + lldb::RegisterContextSP ®_ctx_sp, + uint32_t set_idx); + + uint64_t GetByteSize() override; + + lldb::ValueType GetValueType() const override { + return lldb::eValueTypeRegisterSet; + } + + ConstString GetTypeName() override; + + ConstString GetQualifiedTypeName() override; + + size_t CalculateNumChildren(uint32_t max) override; + + ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, + int32_t synthetic_index) override; + + lldb::ValueObjectSP GetChildMemberWithName(const ConstString &name, + bool can_create) override; + + size_t GetIndexOfChildWithName(const ConstString &name) override; + +protected: + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + lldb::RegisterContextSP m_reg_ctx_sp; + const RegisterSet *m_reg_set; + uint32_t m_reg_set_idx; + +private: + friend class ValueObjectRegisterContext; + + ValueObjectRegisterSet(ExecutionContextScope *exe_scope, + lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx); + + //------------------------------------------------------------------ + // For ValueObject only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ValueObjectRegisterSet); +}; + +class ValueObjectRegister : public ValueObject { +public: + ~ValueObjectRegister() override; + + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + lldb::RegisterContextSP ®_ctx_sp, + uint32_t reg_num); + + uint64_t GetByteSize() override; + + lldb::ValueType GetValueType() const override { + return lldb::eValueTypeRegister; + } + + ConstString GetTypeName() override; + + size_t CalculateNumChildren(uint32_t max) override; + + bool SetValueFromCString(const char *value_str, Status &error) override; + + bool SetData(DataExtractor &data, Status &error) override; + + bool ResolveValue(Scalar &scalar) override; + + void + GetExpressionPath(Stream &s, bool qualify_cxx_base_classes, + GetExpressionPathFormat epformat = + eGetExpressionPathFormatDereferencePointers) override; + +protected: + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + lldb::RegisterContextSP m_reg_ctx_sp; + RegisterInfo m_reg_info; + RegisterValue m_reg_value; + ConstString m_type_name; + CompilerType m_compiler_type; + +private: + void ConstructObject(uint32_t reg_num); + + friend class ValueObjectRegisterSet; + + ValueObjectRegister(ValueObject &parent, lldb::RegisterContextSP ®_ctx_sp, + uint32_t reg_num); + ValueObjectRegister(ExecutionContextScope *exe_scope, + lldb::RegisterContextSP ®_ctx_sp, uint32_t reg_num); + + //------------------------------------------------------------------ + // For ValueObject only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ValueObjectRegister); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectRegister_h_ diff --git a/include/lldb/Core/ValueObjectSyntheticFilter.h b/include/lldb/Core/ValueObjectSyntheticFilter.h new file mode 100644 index 000000000..e32e14030 --- /dev/null +++ b/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -0,0 +1,178 @@ +//===-- ValueObjectSyntheticFilter.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ValueObjectSyntheticFilter_h_ +#define liblldb_ValueObjectSyntheticFilter_h_ + +#include "lldb/Core/ThreadSafeSTLMap.h" +#include "lldb/Core/ThreadSafeSTLVector.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for ThreadSafeSTLMap::operator= +#include "lldb/lldb-enumerations.h" // for DynamicValueType, Langua... +#include "lldb/lldb-forward.h" // for ValueObjectSP, Synthetic... +#include "lldb/lldb-private-enumerations.h" // for LazyBool, LazyBool::eLaz... + +#include // for uint32_t, uint64_t +#include + +#include // for size_t + +namespace lldb_private { +class Declaration; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class SyntheticChildrenFrontEnd; +} +namespace lldb_private { + +//---------------------------------------------------------------------- +// A ValueObject that obtains its children from some source other than +// real information +// This is currently used to implement Python-based children and filters +// but you can bind it to any source of synthetic information and have +// it behave accordingly +//---------------------------------------------------------------------- +class ValueObjectSynthetic : public ValueObject { +public: + ~ValueObjectSynthetic() override; + + uint64_t GetByteSize() override; + + ConstString GetTypeName() override; + + ConstString GetQualifiedTypeName() override; + + ConstString GetDisplayTypeName() override; + + bool MightHaveChildren() override; + + size_t CalculateNumChildren(uint32_t max) override; + + lldb::ValueType GetValueType() const override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create) override; + + lldb::ValueObjectSP GetChildMemberWithName(const ConstString &name, + bool can_create) override; + + size_t GetIndexOfChildWithName(const ConstString &name) override; + + lldb::ValueObjectSP + GetDynamicValue(lldb::DynamicValueType valueType) override; + + bool IsInScope() override; + + bool HasSyntheticValue() override { return false; } + + bool IsSynthetic() override { return true; } + + void CalculateSyntheticValue(bool use_synthetic) override {} + + bool IsDynamic() override { + return ((m_parent != nullptr) ? m_parent->IsDynamic() : false); + } + + lldb::ValueObjectSP GetStaticValue() override { + return ((m_parent != nullptr) ? m_parent->GetStaticValue() : GetSP()); + } + + virtual lldb::DynamicValueType GetDynamicValueType() { + return ((m_parent != nullptr) ? m_parent->GetDynamicValueType() + : lldb::eNoDynamicValues); + } + + ValueObject *GetParent() override { + return ((m_parent != nullptr) ? m_parent->GetParent() : nullptr); + } + + const ValueObject *GetParent() const override { + return ((m_parent != nullptr) ? m_parent->GetParent() : nullptr); + } + + lldb::ValueObjectSP GetNonSyntheticValue() override; + + bool CanProvideValue() override; + + bool DoesProvideSyntheticValue() override { + return (UpdateValueIfNeeded(), m_provides_value == eLazyBoolYes); + } + + bool GetIsConstant() const override { return false; } + + bool SetValueFromCString(const char *value_str, Status &error) override; + + void SetFormat(lldb::Format format) override; + + lldb::LanguageType GetPreferredDisplayLanguage() override; + + void SetPreferredDisplayLanguage(lldb::LanguageType); + + bool IsSyntheticChildrenGenerated() override; + + void SetSyntheticChildrenGenerated(bool b) override; + + bool GetDeclaration(Declaration &decl) override; + + uint64_t GetLanguageFlags() override; + + void SetLanguageFlags(uint64_t flags) override; + +protected: + bool UpdateValue() override; + + LazyBool CanUpdateWithInvalidExecutionContext() override { + return eLazyBoolYes; + } + + CompilerType GetCompilerTypeImpl() override; + + virtual void CreateSynthFilter(); + + // we need to hold on to the SyntheticChildren because someone might delete + // the type binding while we are alive + lldb::SyntheticChildrenSP m_synth_sp; + std::unique_ptr m_synth_filter_ap; + + typedef ThreadSafeSTLMap ByIndexMap; + typedef ThreadSafeSTLMap NameToIndexMap; + typedef ThreadSafeSTLVector SyntheticChildrenCache; + + typedef ByIndexMap::iterator ByIndexIterator; + typedef NameToIndexMap::iterator NameToIndexIterator; + + ByIndexMap m_children_byindex; + NameToIndexMap m_name_toindex; + uint32_t m_synthetic_children_count; // FIXME use the ValueObject's + // ChildrenManager instead of a special + // purpose solution + SyntheticChildrenCache m_synthetic_children_cache; + + ConstString m_parent_type_name; + + LazyBool m_might_have_children; + + LazyBool m_provides_value; + +private: + friend class ValueObject; + ValueObjectSynthetic(ValueObject &parent, lldb::SyntheticChildrenSP filter); + + void CopyValueData(ValueObject *source); + + DISALLOW_COPY_AND_ASSIGN(ValueObjectSynthetic); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectSyntheticFilter_h_ diff --git a/include/lldb/Core/ValueObjectVariable.h b/include/lldb/Core/ValueObjectVariable.h new file mode 100644 index 000000000..9dd140a84 --- /dev/null +++ b/include/lldb/Core/ValueObjectVariable.h @@ -0,0 +1,103 @@ +//===-- 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_ + +#include "lldb/Core/ValueObject.h" + +#include "lldb/Core/Value.h" // for Value +#include "lldb/Symbol/CompilerType.h" // for CompilerType +#include "lldb/Utility/ConstString.h" // for ConstString +#include "lldb/lldb-defines.h" // for DISALLOW_COPY_AND_ASSIGN +#include "lldb/lldb-enumerations.h" // for ValueType +#include "lldb/lldb-forward.h" // for VariableSP, ModuleSP, ValueObj... + +#include // for size_t +#include // for uint32_t, uint64_t + +namespace lldb_private { +class DataExtractor; +} +namespace lldb_private { +class Declaration; +} +namespace lldb_private { +class Status; +} +namespace lldb_private { +class ExecutionContextScope; +} +namespace lldb_private { +class SymbolContextScope; +} + +namespace lldb_private { + +//---------------------------------------------------------------------- +// A ValueObject that contains a root variable that may or may not +// have children. +//---------------------------------------------------------------------- +class ValueObjectVariable : public ValueObject { +public: + ~ValueObjectVariable() override; + + static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, + const lldb::VariableSP &var_sp); + + uint64_t GetByteSize() override; + + ConstString GetTypeName() override; + + ConstString GetQualifiedTypeName() override; + + ConstString GetDisplayTypeName() override; + + size_t CalculateNumChildren(uint32_t max) override; + + lldb::ValueType GetValueType() const override; + + bool IsInScope() override; + + lldb::ModuleSP GetModule() override; + + SymbolContextScope *GetSymbolContextScope() override; + + bool GetDeclaration(Declaration &decl) override; + + const char *GetLocationAsCString() override; + + bool SetValueFromCString(const char *value_str, Status &error) override; + + bool SetData(DataExtractor &data, Status &error) override; + + virtual lldb::VariableSP GetVariable() override { return m_variable_sp; } + +protected: + bool UpdateValue() override; + + CompilerType GetCompilerTypeImpl() override; + + lldb::VariableSP + m_variable_sp; ///< The variable that this value object is based upon + Value m_resolved_value; ///< The value that DWARFExpression resolves this + ///variable to before we patch it up + +private: + ValueObjectVariable(ExecutionContextScope *exe_scope, + const lldb::VariableSP &var_sp); + //------------------------------------------------------------------ + // For ValueObject only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(ValueObjectVariable); +}; + +} // namespace lldb_private + +#endif // liblldb_ValueObjectVariable_h_ diff --git a/include/lldb/Core/dwarf.h b/include/lldb/Core/dwarf.h new file mode 100644 index 000000000..651a2bc29 --- /dev/null +++ b/include/lldb/Core/dwarf.h @@ -0,0 +1,85 @@ +//===-- 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 + +// Get the DWARF constant definitions from llvm +#include "llvm/BinaryFormat/Dwarf.h" + +#include "lldb/Core/RangeMap.h" + +// and stuff them in our default namespace +using namespace llvm::dwarf; + +typedef uint32_t dw_uleb128_t; +typedef int32_t dw_sleb128_t; +typedef uint16_t dw_attr_t; +typedef uint16_t dw_form_t; +typedef uint16_t dw_tag_t; +typedef uint64_t dw_addr_t; // Dwarf address define that must be big enough for + // any addresses in the compile units that get + // parsed + +#ifdef DWARFUTILS_DWARF64 +#define DWARF_REF_ADDR_SIZE 8 +typedef uint64_t dw_offset_t; // Dwarf Debug Information Entry offset for any + // offset into the file +#else +#define DWARF_REF_ADDR_SIZE 4 +typedef uint32_t dw_offset_t; // Dwarf Debug Information Entry offset for any + // offset into the file +#endif + +/* Constants */ +#define DW_INVALID_OFFSET (~(dw_offset_t)0) +#define DW_INVALID_INDEX 0xFFFFFFFFul + +// #define DW_ADDR_none 0x0 + +#define DW_EH_PE_MASK_ENCODING 0x0F + +//// The following are used only internally within lldb - don't +//// document them in the llvm Dwarf.h header file, we won't see +//// them in executable files anywhere. +//// These constants fit between DW_OP_lo_user (0xe0) and DW_OP_hi_user (0xff). +// +//#define DW_OP_APPLE_array_ref 0xEE // first pops index, then pops array; +//pushes array[index] +//#define DW_OP_APPLE_extern 0xEF // ULEB128 index of external object +//(i.e., an entity from the program that was used in the expression) +#define DW_OP_APPLE_uninit \ + 0xF0 // This is actually generated by some apple compilers in locations lists +//#define DW_OP_APPLE_assign 0xF1 // pops value off and assigns it to +//second item on stack (2nd item must have assignable context) +//#define DW_OP_APPLE_address_of 0xF2 // gets the address of the top stack +//item (top item must be a variable, or have value_type that is an address +//already) +//#define DW_OP_APPLE_value_of 0xF3 // pops the value off the stack and +//pushes the value of that object (top item must be a variable, or expression +//local) +//#define DW_OP_APPLE_deref_type 0xF4 // gets the address of the top stack +//item (top item must be a variable, or a clang type) +//#define DW_OP_APPLE_expr_local 0xF5 // ULEB128 expression local index +//#define DW_OP_APPLE_constf 0xF6 // 1 byte float size, followed by +//constant float data +//#define DW_OP_APPLE_scalar_cast 0xF7 // Cast top of stack to 2nd in stack's +//type leaving all items in place +//#define DW_OP_APPLE_clang_cast 0xF8 // pointer size clang::Type * off the +//stack and cast top stack item to this type +//#define DW_OP_APPLE_clear 0xFE // clears the entire expression stack, +//ok if the stack is empty +//#define DW_OP_APPLE_error 0xFF // Stops expression evaluation and +//returns an error (no args) + +typedef lldb_private::RangeArray DWARFRangeList; + +#endif // DebugBase_dwarf_h_ diff --git a/include/lldb/DataFormatters/CXXFunctionPointer.h b/include/lldb/DataFormatters/CXXFunctionPointer.h new file mode 100644 index 000000000..13af2fd9d --- /dev/null +++ b/include/lldb/DataFormatters/CXXFunctionPointer.h @@ -0,0 +1,22 @@ +//===-- CXXFunctionPointer.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CXXFunctionPointer_h_ +#define liblldb_CXXFunctionPointer_h_ + +#include "lldb/lldb-forward.h" + +namespace lldb_private { +namespace formatters { +bool CXXFunctionPointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_CXXFunctionPointer_h_ diff --git a/include/lldb/DataFormatters/DataVisualization.h b/include/lldb/DataFormatters/DataVisualization.h new file mode 100644 index 000000000..343099bf2 --- /dev/null +++ b/include/lldb/DataFormatters/DataVisualization.h @@ -0,0 +1,146 @@ +//===-- DataVisualization.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_DataVisualization_h_ +#define lldb_DataVisualization_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes +// Project includes +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Utility/ConstString.h" + +namespace lldb_private { + +// this class is the high-level front-end of LLDB Data Visualization +// code in FormatManager.h/cpp is the low-level implementation of this feature +// clients should refer to this class as the entry-point into the data +// formatters +// unless they have a good reason to bypass this and go to the backend +class DataVisualization { +public: + // use this call to force the FM to consider itself updated even when there is + // no apparent reason for that + static void ForceUpdate(); + + static uint32_t GetCurrentRevision(); + + static bool ShouldPrintAsOneLiner(ValueObject &valobj); + + static lldb::TypeFormatImplSP GetFormat(ValueObject &valobj, + lldb::DynamicValueType use_dynamic); + + static lldb::TypeFormatImplSP + GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp); + + static lldb::TypeSummaryImplSP + GetSummaryFormat(ValueObject &valobj, lldb::DynamicValueType use_dynamic); + + static lldb::TypeSummaryImplSP + GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp); + +#ifndef LLDB_DISABLE_PYTHON + static lldb::SyntheticChildrenSP + GetSyntheticChildrenForType(lldb::TypeNameSpecifierImplSP type_sp); +#endif + + static lldb::TypeFilterImplSP + GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp); + +#ifndef LLDB_DISABLE_PYTHON + static lldb::ScriptedSyntheticChildrenSP + GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp); +#endif + +#ifndef LLDB_DISABLE_PYTHON + static lldb::SyntheticChildrenSP + GetSyntheticChildren(ValueObject &valobj, lldb::DynamicValueType use_dynamic); +#endif + + static lldb::TypeValidatorImplSP + GetValidator(ValueObject &valobj, lldb::DynamicValueType use_dynamic); + + static lldb::TypeValidatorImplSP + GetValidatorForType(lldb::TypeNameSpecifierImplSP type_sp); + + static bool + AnyMatches(ConstString type_name, + TypeCategoryImpl::FormatCategoryItems items = + TypeCategoryImpl::ALL_ITEM_TYPES, + bool only_enabled = true, const char **matching_category = nullptr, + TypeCategoryImpl::FormatCategoryItems *matching_type = nullptr); + + class NamedSummaryFormats { + public: + static bool GetSummaryFormat(const ConstString &type, + lldb::TypeSummaryImplSP &entry); + + static void Add(const ConstString &type, + const lldb::TypeSummaryImplSP &entry); + + static bool Delete(const ConstString &type); + + static void Clear(); + + static void + ForEach(std::function + callback); + + static uint32_t GetCount(); + }; + + class Categories { + public: + static bool GetCategory(const ConstString &category, + lldb::TypeCategoryImplSP &entry, + bool allow_create = true); + + static bool GetCategory(lldb::LanguageType language, + lldb::TypeCategoryImplSP &entry); + + static void Add(const ConstString &category); + + static bool Delete(const ConstString &category); + + static void Clear(); + + static void Clear(const ConstString &category); + + static void Enable(const ConstString &category, + TypeCategoryMap::Position = TypeCategoryMap::Default); + + static void Enable(lldb::LanguageType lang_type); + + static void Disable(const ConstString &category); + + static void Disable(lldb::LanguageType lang_type); + + static void Enable(const lldb::TypeCategoryImplSP &category, + TypeCategoryMap::Position = TypeCategoryMap::Default); + + static void Disable(const lldb::TypeCategoryImplSP &category); + + static void EnableStar(); + + static void DisableStar(); + + static void ForEach(TypeCategoryMap::ForEachCallback callback); + + static uint32_t GetCount(); + + static lldb::TypeCategoryImplSP GetCategoryAtIndex(size_t); + }; +}; + +} // namespace lldb_private + +#endif // lldb_DataVisualization_h_ diff --git a/include/lldb/DataFormatters/DumpValueObjectOptions.h b/include/lldb/DataFormatters/DumpValueObjectOptions.h new file mode 100644 index 000000000..00baea77f --- /dev/null +++ b/include/lldb/DataFormatters/DumpValueObjectOptions.h @@ -0,0 +1,165 @@ +//===-- DumpValueObjectOptions.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_DumpValueObjectOptions_h_ +#define lldb_DumpValueObjectOptions_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/lldb-public.h" + +#include +#include + +namespace lldb_private { + +class DumpValueObjectOptions { +public: + struct PointerDepth { + enum class Mode { Always, Default, Never } m_mode; + uint32_t m_count; + + PointerDepth operator--() const { + if (m_count > 0) + return PointerDepth{m_mode, m_count - 1}; + return PointerDepth{m_mode, m_count}; + } + + bool CanAllowExpansion() const; + }; + + struct PointerAsArraySettings { + size_t m_element_count; + size_t m_base_element; + size_t m_stride; + + PointerAsArraySettings() + : m_element_count(0), m_base_element(0), m_stride() {} + + PointerAsArraySettings(size_t elem_count, size_t base_elem = 0, + size_t stride = 1) + : m_element_count(elem_count), m_base_element(base_elem), + m_stride(stride) {} + + operator bool() { return m_element_count > 0; } + }; + + typedef std::function + DeclPrintingHelper; + + static const DumpValueObjectOptions DefaultOptions() { + static DumpValueObjectOptions g_default_options; + + return g_default_options; + } + + DumpValueObjectOptions(); + + DumpValueObjectOptions(const DumpValueObjectOptions &rhs) = default; + + DumpValueObjectOptions(ValueObject &valobj); + + DumpValueObjectOptions & + SetMaximumPointerDepth(PointerDepth depth = {PointerDepth::Mode::Never, 0}); + + DumpValueObjectOptions &SetMaximumDepth(uint32_t depth = 0); + + DumpValueObjectOptions &SetDeclPrintingHelper(DeclPrintingHelper helper); + + DumpValueObjectOptions &SetShowTypes(bool show = false); + + DumpValueObjectOptions &SetShowLocation(bool show = false); + + DumpValueObjectOptions &SetUseObjectiveC(bool use = false); + + DumpValueObjectOptions &SetShowSummary(bool show = true); + + DumpValueObjectOptions & + SetUseDynamicType(lldb::DynamicValueType dyn = lldb::eNoDynamicValues); + + DumpValueObjectOptions &SetUseSyntheticValue(bool use_synthetic = true); + + DumpValueObjectOptions &SetScopeChecked(bool check = true); + + DumpValueObjectOptions &SetFlatOutput(bool flat = false); + + DumpValueObjectOptions &SetOmitSummaryDepth(uint32_t depth = 0); + + DumpValueObjectOptions &SetIgnoreCap(bool ignore = false); + + DumpValueObjectOptions &SetRawDisplay(); + + DumpValueObjectOptions &SetFormat(lldb::Format format = lldb::eFormatDefault); + + DumpValueObjectOptions & + SetSummary(lldb::TypeSummaryImplSP summary = lldb::TypeSummaryImplSP()); + + DumpValueObjectOptions &SetRootValueObjectName(const char *name = nullptr); + + DumpValueObjectOptions &SetHideRootType(bool hide_root_type = false); + + DumpValueObjectOptions &SetHideName(bool hide_name = false); + + DumpValueObjectOptions &SetHideValue(bool hide_value = false); + + DumpValueObjectOptions &SetHidePointerValue(bool hide = false); + + DumpValueObjectOptions &SetVariableFormatDisplayLanguage( + lldb::LanguageType lang = lldb::eLanguageTypeUnknown); + + DumpValueObjectOptions &SetRunValidator(bool run = true); + + DumpValueObjectOptions &SetUseTypeDisplayName(bool dis = false); + + DumpValueObjectOptions &SetAllowOnelinerMode(bool oneliner = false); + + DumpValueObjectOptions &SetRevealEmptyAggregates(bool reveal = true); + + DumpValueObjectOptions &SetElementCount(uint32_t element_count = 0); + + DumpValueObjectOptions & + SetPointerAsArray(const PointerAsArraySettings &ptr_array); + +public: + uint32_t m_max_depth = UINT32_MAX; + lldb::DynamicValueType m_use_dynamic = lldb::eNoDynamicValues; + uint32_t m_omit_summary_depth = 0; + lldb::Format m_format = lldb::eFormatDefault; + lldb::TypeSummaryImplSP m_summary_sp; + std::string m_root_valobj_name; + lldb::LanguageType m_varformat_language = lldb::eLanguageTypeUnknown; + PointerDepth m_max_ptr_depth; + DeclPrintingHelper m_decl_printing_helper; + PointerAsArraySettings m_pointer_as_array; + bool m_use_synthetic : 1; + bool m_scope_already_checked : 1; + bool m_flat_output : 1; + bool m_ignore_cap : 1; + bool m_show_types : 1; + bool m_show_location : 1; + bool m_use_objc : 1; + bool m_hide_root_type : 1; + bool m_hide_name : 1; + bool m_hide_value : 1; + bool m_run_validator : 1; + bool m_use_type_display_name : 1; + bool m_allow_oneliner_mode : 1; + bool m_hide_pointer_value : 1; + bool m_reveal_empty_aggregates : 1; +}; + +} // namespace lldb_private + +#endif // lldb_DumpValueObjectOptions_h_ diff --git a/include/lldb/DataFormatters/FormatCache.h b/include/lldb/DataFormatters/FormatCache.h new file mode 100644 index 000000000..9901ec91e --- /dev/null +++ b/include/lldb/DataFormatters/FormatCache.h @@ -0,0 +1,112 @@ +//===-- FormatCache.h ---------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_FormatCache_h_ +#define lldb_FormatCache_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { +class FormatCache { +private: + struct Entry { + private: + bool m_format_cached : 1; + bool m_summary_cached : 1; + bool m_synthetic_cached : 1; + bool m_validator_cached : 1; + + lldb::TypeFormatImplSP m_format_sp; + lldb::TypeSummaryImplSP m_summary_sp; + lldb::SyntheticChildrenSP m_synthetic_sp; + lldb::TypeValidatorImplSP m_validator_sp; + + public: + Entry(); + Entry(lldb::TypeFormatImplSP); + Entry(lldb::TypeSummaryImplSP); + Entry(lldb::SyntheticChildrenSP); + Entry(lldb::TypeValidatorImplSP); + Entry(lldb::TypeFormatImplSP, lldb::TypeSummaryImplSP, + lldb::SyntheticChildrenSP, lldb::TypeValidatorImplSP); + + bool IsFormatCached(); + + bool IsSummaryCached(); + + bool IsSyntheticCached(); + + bool IsValidatorCached(); + + lldb::TypeFormatImplSP GetFormat(); + + lldb::TypeSummaryImplSP GetSummary(); + + lldb::SyntheticChildrenSP GetSynthetic(); + + lldb::TypeValidatorImplSP GetValidator(); + + void SetFormat(lldb::TypeFormatImplSP); + + void SetSummary(lldb::TypeSummaryImplSP); + + void SetSynthetic(lldb::SyntheticChildrenSP); + + void SetValidator(lldb::TypeValidatorImplSP); + }; + typedef std::map CacheMap; + CacheMap m_map; + std::recursive_mutex m_mutex; + + uint64_t m_cache_hits; + uint64_t m_cache_misses; + + Entry &GetEntry(const ConstString &type); + +public: + FormatCache(); + + bool GetFormat(const ConstString &type, lldb::TypeFormatImplSP &format_sp); + + bool GetSummary(const ConstString &type, lldb::TypeSummaryImplSP &summary_sp); + + bool GetSynthetic(const ConstString &type, + lldb::SyntheticChildrenSP &synthetic_sp); + + bool GetValidator(const ConstString &type, + lldb::TypeValidatorImplSP &summary_sp); + + void SetFormat(const ConstString &type, lldb::TypeFormatImplSP &format_sp); + + void SetSummary(const ConstString &type, lldb::TypeSummaryImplSP &summary_sp); + + void SetSynthetic(const ConstString &type, + lldb::SyntheticChildrenSP &synthetic_sp); + + void SetValidator(const ConstString &type, + lldb::TypeValidatorImplSP &synthetic_sp); + + void Clear(); + + uint64_t GetCacheHits() { return m_cache_hits; } + + uint64_t GetCacheMisses() { return m_cache_misses; } +}; +} // namespace lldb_private + +#endif // lldb_FormatCache_h_ diff --git a/include/lldb/DataFormatters/FormatClasses.h b/include/lldb/DataFormatters/FormatClasses.h new file mode 100644 index 000000000..c559c212c --- /dev/null +++ b/include/lldb/DataFormatters/FormatClasses.h @@ -0,0 +1,177 @@ +//===-- FormatClasses.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_FormatClasses_h_ +#define lldb_FormatClasses_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/DataFormatters/TypeFormat.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/DataFormatters/TypeValidator.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/Type.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { + +class HardcodedFormatters { +public: + template + using HardcodedFormatterFinder = + std::function; + + template + using HardcodedFormatterFinders = + std::vector>; + + typedef HardcodedFormatterFinders HardcodedFormatFinder; + typedef HardcodedFormatterFinders HardcodedSummaryFinder; + typedef HardcodedFormatterFinders HardcodedSyntheticFinder; + typedef HardcodedFormatterFinders HardcodedValidatorFinder; +}; + +class FormattersMatchCandidate { +public: + FormattersMatchCandidate(ConstString name, uint32_t reason, bool strip_ptr, + bool strip_ref, bool strip_tydef) + : m_type_name(name), m_reason(reason), m_stripped_pointer(strip_ptr), + m_stripped_reference(strip_ref), m_stripped_typedef(strip_tydef) {} + + ~FormattersMatchCandidate() = default; + + ConstString GetTypeName() const { return m_type_name; } + + uint32_t GetReason() const { return m_reason; } + + bool DidStripPointer() const { return m_stripped_pointer; } + + bool DidStripReference() const { return m_stripped_reference; } + + bool DidStripTypedef() const { return m_stripped_typedef; } + + template + bool IsMatch(const std::shared_ptr &formatter_sp) const { + if (!formatter_sp) + return false; + if (formatter_sp->Cascades() == false && DidStripTypedef()) + return false; + if (formatter_sp->SkipsPointers() && DidStripPointer()) + return false; + if (formatter_sp->SkipsReferences() && DidStripReference()) + return false; + return true; + } + +private: + ConstString m_type_name; + uint32_t m_reason; + bool m_stripped_pointer; + bool m_stripped_reference; + bool m_stripped_typedef; +}; + +typedef std::vector FormattersMatchVector; +typedef std::vector CandidateLanguagesVector; + +class FormattersMatchData { +public: + FormattersMatchData(ValueObject &, lldb::DynamicValueType); + + FormattersMatchVector GetMatchesVector(); + + ConstString GetTypeForCache(); + + CandidateLanguagesVector GetCandidateLanguages(); + + ValueObject &GetValueObject(); + + lldb::DynamicValueType GetDynamicValueType(); + +private: + ValueObject &m_valobj; + lldb::DynamicValueType m_dynamic_value_type; + std::pair m_formatters_match_vector; + ConstString m_type_for_cache; + CandidateLanguagesVector m_candidate_languages; +}; + +class TypeNameSpecifierImpl { +public: + TypeNameSpecifierImpl() : m_is_regex(false), m_type() {} + + TypeNameSpecifierImpl(llvm::StringRef name, bool is_regex) + : m_is_regex(is_regex), m_type() { + m_type.m_type_name = name; + } + + // if constructing with a given type, is_regex cannot be true since we are + // giving an exact type to match + TypeNameSpecifierImpl(lldb::TypeSP type) : m_is_regex(false), m_type() { + if (type) { + m_type.m_type_name = type->GetName().GetStringRef(); + m_type.m_type_pair.SetType(type); + } + } + + TypeNameSpecifierImpl(CompilerType type) : m_is_regex(false), m_type() { + if (type.IsValid()) { + m_type.m_type_name.assign(type.GetConstTypeName().GetCString()); + m_type.m_type_pair.SetType(type); + } + } + + const char *GetName() { + if (m_type.m_type_name.size()) + return m_type.m_type_name.c_str(); + return nullptr; + } + + lldb::TypeSP GetTypeSP() { + if (m_type.m_type_pair.IsValid()) + return m_type.m_type_pair.GetTypeSP(); + return lldb::TypeSP(); + } + + CompilerType GetCompilerType() { + if (m_type.m_type_pair.IsValid()) + return m_type.m_type_pair.GetCompilerType(); + return CompilerType(); + } + + bool IsRegex() { return m_is_regex; } + +private: + bool m_is_regex; + // this works better than TypeAndOrName because the latter only wraps a TypeSP + // whereas TypePair can also be backed by a CompilerType + struct TypeOrName { + std::string m_type_name; + TypePair m_type_pair; + }; + TypeOrName m_type; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeNameSpecifierImpl); +}; + +} // namespace lldb_private + +#endif // lldb_FormatClasses_h_ diff --git a/include/lldb/DataFormatters/FormatManager.h b/include/lldb/DataFormatters/FormatManager.h new file mode 100644 index 000000000..924ef0cdf --- /dev/null +++ b/include/lldb/DataFormatters/FormatManager.h @@ -0,0 +1,270 @@ +//===-- FormatManager.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_FormatManager_h_ +#define lldb_FormatManager_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +#include "lldb/DataFormatters/FormatCache.h" +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/FormattersContainer.h" +#include "lldb/DataFormatters/LanguageCategory.h" +#include "lldb/DataFormatters/TypeCategory.h" +#include "lldb/DataFormatters/TypeCategoryMap.h" + +namespace lldb_private { + +// this file (and its. cpp) contain the low-level implementation of LLDB Data +// Visualization +// class DataVisualization is the high-level front-end of this feature +// clients should refer to that class as the entry-point into the data +// formatters +// unless they have a good reason to bypass it and prefer to use this file's +// objects directly + +class FormatManager : public IFormatChangeListener { + typedef FormatMap NamedSummariesMap; + typedef TypeCategoryMap::MapType::iterator CategoryMapIterator; + +public: + typedef std::map + LanguageCategories; + + FormatManager(); + + ~FormatManager() override = default; + + NamedSummariesMap &GetNamedSummaryContainer() { + return m_named_summaries_map; + } + + void + EnableCategory(const ConstString &category_name, + TypeCategoryMap::Position pos = TypeCategoryMap::Default) { + EnableCategory(category_name, pos, + std::initializer_list()); + } + + void EnableCategory(const ConstString &category_name, + TypeCategoryMap::Position pos, lldb::LanguageType lang) { + std::initializer_list langs = {lang}; + EnableCategory(category_name, pos, langs); + } + + void EnableCategory(const ConstString &category_name, + TypeCategoryMap::Position pos = TypeCategoryMap::Default, + std::initializer_list langs = {}) { + TypeCategoryMap::ValueSP category_sp; + if (m_categories_map.Get(category_name, category_sp) && category_sp) { + m_categories_map.Enable(category_sp, pos); + for (const lldb::LanguageType lang : langs) + category_sp->AddLanguage(lang); + } + } + + void DisableCategory(const ConstString &category_name) { + m_categories_map.Disable(category_name); + } + + void + EnableCategory(const lldb::TypeCategoryImplSP &category, + TypeCategoryMap::Position pos = TypeCategoryMap::Default) { + m_categories_map.Enable(category, pos); + } + + void DisableCategory(const lldb::TypeCategoryImplSP &category) { + m_categories_map.Disable(category); + } + + void EnableAllCategories(); + + void DisableAllCategories(); + + bool DeleteCategory(const ConstString &category_name) { + return m_categories_map.Delete(category_name); + } + + void ClearCategories() { return m_categories_map.Clear(); } + + uint32_t GetCategoriesCount() { return m_categories_map.GetCount(); } + + lldb::TypeCategoryImplSP GetCategoryAtIndex(size_t index) { + return m_categories_map.GetAtIndex(index); + } + + void ForEachCategory(TypeCategoryMap::ForEachCallback callback); + + lldb::TypeCategoryImplSP GetCategory(const char *category_name = nullptr, + bool can_create = true) { + if (!category_name) + return GetCategory(m_default_category_name); + return GetCategory(ConstString(category_name)); + } + + lldb::TypeCategoryImplSP GetCategory(const ConstString &category_name, + bool can_create = true); + + lldb::TypeFormatImplSP + GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp); + + lldb::TypeSummaryImplSP + GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp); + + lldb::TypeFilterImplSP + GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp); + +#ifndef LLDB_DISABLE_PYTHON + lldb::ScriptedSyntheticChildrenSP + GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp); +#endif + +#ifndef LLDB_DISABLE_PYTHON + lldb::SyntheticChildrenSP + GetSyntheticChildrenForType(lldb::TypeNameSpecifierImplSP type_sp); +#endif + + lldb::TypeValidatorImplSP + GetValidatorForType(lldb::TypeNameSpecifierImplSP type_sp); + + lldb::TypeFormatImplSP GetFormat(ValueObject &valobj, + lldb::DynamicValueType use_dynamic); + + lldb::TypeSummaryImplSP GetSummaryFormat(ValueObject &valobj, + lldb::DynamicValueType use_dynamic); + +#ifndef LLDB_DISABLE_PYTHON + lldb::SyntheticChildrenSP + GetSyntheticChildren(ValueObject &valobj, lldb::DynamicValueType use_dynamic); +#endif + + lldb::TypeValidatorImplSP GetValidator(ValueObject &valobj, + lldb::DynamicValueType use_dynamic); + + bool + AnyMatches(ConstString type_name, + TypeCategoryImpl::FormatCategoryItems items = + TypeCategoryImpl::ALL_ITEM_TYPES, + bool only_enabled = true, const char **matching_category = nullptr, + TypeCategoryImpl::FormatCategoryItems *matching_type = nullptr) { + return m_categories_map.AnyMatches(type_name, items, only_enabled, + matching_category, matching_type); + } + + static bool GetFormatFromCString(const char *format_cstr, + bool partial_match_ok, lldb::Format &format); + + static char GetFormatAsFormatChar(lldb::Format format); + + static const char *GetFormatAsCString(lldb::Format format); + + // if the user tries to add formatters for, say, "struct Foo" + // those will not match any type because of the way we strip qualifiers from + // typenames + // this method looks for the case where the user is adding a + // "class","struct","enum" or "union" Foo + // and strips the unnecessary qualifier + static ConstString GetValidTypeName(const ConstString &type); + + // when DataExtractor dumps a vectorOfT, it uses a predefined format for each + // item + // this method returns it, or eFormatInvalid if vector_format is not a + // vectorOf + static lldb::Format GetSingleItemFormat(lldb::Format vector_format); + + // this returns true if the ValueObjectPrinter is *highly encouraged* + // to actually represent this ValueObject in one-liner format + // If this object has a summary formatter, however, we should not + // try and do one-lining, just let the summary do the right thing + bool ShouldPrintAsOneLiner(ValueObject &valobj); + + void Changed() override; + + uint32_t GetCurrentRevision() override { return m_last_revision; } + + static FormattersMatchVector + GetPossibleMatches(ValueObject &valobj, lldb::DynamicValueType use_dynamic) { + FormattersMatchVector matches; + GetPossibleMatches(valobj, valobj.GetCompilerType(), + lldb_private::eFormatterChoiceCriterionDirectChoice, + use_dynamic, matches, false, false, false, true); + return matches; + } + + static ConstString GetTypeForCache(ValueObject &, lldb::DynamicValueType); + + LanguageCategory *GetCategoryForLanguage(lldb::LanguageType lang_type); + + static std::vector + GetCandidateLanguages(lldb::LanguageType lang_type); + +private: + static std::vector + GetCandidateLanguages(ValueObject &valobj); + + static void GetPossibleMatches(ValueObject &valobj, + CompilerType compiler_type, uint32_t reason, + lldb::DynamicValueType use_dynamic, + FormattersMatchVector &entries, + bool did_strip_ptr, bool did_strip_ref, + bool did_strip_typedef, + bool root_level = false); + + std::atomic m_last_revision; + FormatCache m_format_cache; + std::recursive_mutex m_language_categories_mutex; + LanguageCategories m_language_categories_map; + NamedSummariesMap m_named_summaries_map; + TypeCategoryMap m_categories_map; + + ConstString m_default_category_name; + ConstString m_system_category_name; + ConstString m_vectortypes_category_name; + + lldb::TypeFormatImplSP GetHardcodedFormat(FormattersMatchData &); + + lldb::TypeSummaryImplSP GetHardcodedSummaryFormat(FormattersMatchData &); + + lldb::SyntheticChildrenSP + GetHardcodedSyntheticChildren(FormattersMatchData &); + + lldb::TypeValidatorImplSP GetHardcodedValidator(FormattersMatchData &); + + TypeCategoryMap &GetCategories() { return m_categories_map; } + + // These functions are meant to initialize formatters that are very + // low-level/global in nature + // and do not naturally belong in any language. The intent is that most + // formatters go in + // language-specific categories. Eventually, the runtimes should also be + // allowed to vend their + // own formatters, and then one could put formatters that depend on specific + // library load events + // in the language runtimes, on an as-needed basis + void LoadSystemFormatters(); + + void LoadVectorFormatters(); + + friend class FormattersMatchData; +}; + +} // namespace lldb_private + +#endif // lldb_FormatManager_h_ diff --git a/include/lldb/DataFormatters/FormattersContainer.h b/include/lldb/DataFormatters/FormattersContainer.h new file mode 100644 index 000000000..2df5bf4ef --- /dev/null +++ b/include/lldb/DataFormatters/FormattersContainer.h @@ -0,0 +1,350 @@ +//===-- FormattersContainer.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_FormattersContainer_h_ +#define lldb_FormattersContainer_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-public.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/TypeFormat.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/DataFormatters/TypeValidator.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/StringLexer.h" + +namespace lldb_private { + +class IFormatChangeListener { +public: + virtual ~IFormatChangeListener() = default; + + virtual void Changed() = 0; + + virtual uint32_t GetCurrentRevision() = 0; +}; + +// if the user tries to add formatters for, say, "struct Foo" +// those will not match any type because of the way we strip qualifiers from +// typenames +// this method looks for the case where the user is adding a +// "class","struct","enum" or "union" Foo +// and strips the unnecessary qualifier +static inline ConstString GetValidTypeName_Impl(const ConstString &type) { + if (type.IsEmpty()) + return type; + + std::string type_cstr(type.AsCString()); + lldb_utility::StringLexer type_lexer(type_cstr); + + type_lexer.AdvanceIf("class "); + type_lexer.AdvanceIf("enum "); + type_lexer.AdvanceIf("struct "); + type_lexer.AdvanceIf("union "); + + while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) + ; + + return ConstString(type_lexer.GetUnlexed()); +} + +template class FormattersContainer; + +template class FormatMap { +public: + typedef typename ValueType::SharedPointer ValueSP; + typedef std::map MapType; + typedef typename MapType::iterator MapIterator; + typedef std::function ForEachCallback; + + FormatMap(IFormatChangeListener *lst) + : m_map(), m_map_mutex(), listener(lst) {} + + void Add(KeyType name, const ValueSP &entry) { + if (listener) + entry->GetRevision() = listener->GetCurrentRevision(); + else + entry->GetRevision() = 0; + + std::lock_guard guard(m_map_mutex); + m_map[name] = entry; + if (listener) + listener->Changed(); + } + + bool Delete(KeyType name) { + std::lock_guard guard(m_map_mutex); + MapIterator iter = m_map.find(name); + if (iter == m_map.end()) + return false; + m_map.erase(name); + if (listener) + listener->Changed(); + return true; + } + + void Clear() { + std::lock_guard guard(m_map_mutex); + m_map.clear(); + if (listener) + listener->Changed(); + } + + bool Get(KeyType name, ValueSP &entry) { + std::lock_guard guard(m_map_mutex); + MapIterator iter = m_map.find(name); + if (iter == m_map.end()) + return false; + entry = iter->second; + return true; + } + + void ForEach(ForEachCallback callback) { + if (callback) { + std::lock_guard guard(m_map_mutex); + MapIterator pos, end = m_map.end(); + for (pos = m_map.begin(); pos != end; pos++) { + KeyType type = pos->first; + if (!callback(type, pos->second)) + break; + } + } + } + + uint32_t GetCount() { return m_map.size(); } + + ValueSP GetValueAtIndex(size_t index) { + std::lock_guard guard(m_map_mutex); + MapIterator iter = m_map.begin(); + MapIterator end = m_map.end(); + while (index > 0) { + iter++; + index--; + if (end == iter) + return ValueSP(); + } + return iter->second; + } + + KeyType GetKeyAtIndex(size_t index) { + std::lock_guard guard(m_map_mutex); + MapIterator iter = m_map.begin(); + MapIterator end = m_map.end(); + while (index > 0) { + iter++; + index--; + if (end == iter) + return KeyType(); + } + return iter->first; + } + +protected: + MapType m_map; + std::recursive_mutex m_map_mutex; + IFormatChangeListener *listener; + + MapType &map() { return m_map; } + + std::recursive_mutex &mutex() { return m_map_mutex; } + + friend class FormattersContainer; + friend class FormatManager; +}; + +template class FormattersContainer { +protected: + typedef FormatMap BackEndType; + +public: + typedef typename BackEndType::MapType MapType; + typedef typename MapType::iterator MapIterator; + typedef typename MapType::key_type MapKeyType; + typedef typename MapType::mapped_type MapValueType; + typedef typename BackEndType::ForEachCallback ForEachCallback; + typedef typename std::shared_ptr> + SharedPointer; + + friend class TypeCategoryImpl; + + FormattersContainer(std::string name, IFormatChangeListener *lst) + : m_format_map(lst), m_name(name) {} + + void Add(const MapKeyType &type, const MapValueType &entry) { + Add_Impl(type, entry, static_cast(nullptr)); + } + + bool Delete(ConstString type) { + return Delete_Impl(type, static_cast(nullptr)); + } + + bool Get(ValueObject &valobj, MapValueType &entry, + lldb::DynamicValueType use_dynamic, uint32_t *why = nullptr) { + uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice; + CompilerType ast_type(valobj.GetCompilerType()); + bool ret = Get(valobj, ast_type, entry, use_dynamic, value); + if (ret) + entry = MapValueType(entry); + else + entry = MapValueType(); + if (why) + *why = value; + return ret; + } + + bool Get(ConstString type, MapValueType &entry) { + return Get_Impl(type, entry, static_cast(nullptr)); + } + + bool GetExact(ConstString type, MapValueType &entry) { + return GetExact_Impl(type, entry, static_cast(nullptr)); + } + + MapValueType GetAtIndex(size_t index) { + return m_format_map.GetValueAtIndex(index); + } + + lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { + return GetTypeNameSpecifierAtIndex_Impl(index, + static_cast(nullptr)); + } + + void Clear() { m_format_map.Clear(); } + + void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); } + + uint32_t GetCount() { return m_format_map.GetCount(); } + +protected: + BackEndType m_format_map; + std::string m_name; + + DISALLOW_COPY_AND_ASSIGN(FormattersContainer); + + void Add_Impl(const MapKeyType &type, const MapValueType &entry, + lldb::RegularExpressionSP *dummy) { + m_format_map.Add(type, entry); + } + + void Add_Impl(const ConstString &type, const MapValueType &entry, + ConstString *dummy) { + m_format_map.Add(GetValidTypeName_Impl(type), entry); + } + + bool Delete_Impl(ConstString type, ConstString *dummy) { + return m_format_map.Delete(type); + } + + bool Delete_Impl(ConstString type, lldb::RegularExpressionSP *dummy) { + std::lock_guard guard(m_format_map.mutex()); + MapIterator pos, end = m_format_map.map().end(); + for (pos = m_format_map.map().begin(); pos != end; pos++) { + lldb::RegularExpressionSP regex = pos->first; + if (type.GetStringRef() == regex->GetText()) { + m_format_map.map().erase(pos); + if (m_format_map.listener) + m_format_map.listener->Changed(); + return true; + } + } + return false; + } + + bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { + return m_format_map.Get(type, entry); + } + + bool GetExact_Impl(ConstString type, MapValueType &entry, + ConstString *dummy) { + return Get_Impl(type, entry, static_cast(nullptr)); + } + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) { + ConstString key = m_format_map.GetKeyAtIndex(index); + if (key) + return lldb::TypeNameSpecifierImplSP( + new TypeNameSpecifierImpl(key.AsCString(), false)); + else + return lldb::TypeNameSpecifierImplSP(); + } + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierAtIndex_Impl(size_t index, + lldb::RegularExpressionSP *dummy) { + lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index); + if (regex.get() == nullptr) + return lldb::TypeNameSpecifierImplSP(); + return lldb::TypeNameSpecifierImplSP( + new TypeNameSpecifierImpl(regex->GetText().str().c_str(), true)); + } + + bool Get_Impl(ConstString key, MapValueType &value, + lldb::RegularExpressionSP *dummy) { + llvm::StringRef key_str = key.GetStringRef(); + std::lock_guard guard(m_format_map.mutex()); + MapIterator pos, end = m_format_map.map().end(); + for (pos = m_format_map.map().begin(); pos != end; pos++) { + lldb::RegularExpressionSP regex = pos->first; + if (regex->Execute(key_str)) { + value = pos->second; + return true; + } + } + return false; + } + + bool GetExact_Impl(ConstString key, MapValueType &value, + lldb::RegularExpressionSP *dummy) { + std::lock_guard guard(m_format_map.mutex()); + MapIterator pos, end = m_format_map.map().end(); + for (pos = m_format_map.map().begin(); pos != end; pos++) { + lldb::RegularExpressionSP regex = pos->first; + if (regex->GetText() == key.GetStringRef()) { + value = pos->second; + return true; + } + } + return false; + } + + bool Get(const FormattersMatchVector &candidates, MapValueType &entry, + uint32_t *reason) { + for (const FormattersMatchCandidate &candidate : candidates) { + if (Get(candidate.GetTypeName(), entry)) { + if (candidate.IsMatch(entry) == false) { + entry.reset(); + continue; + } else { + if (reason) + *reason = candidate.GetReason(); + return true; + } + } + } + return false; + } +}; + +} // namespace lldb_private + +#endif // lldb_FormattersContainer_h_ diff --git a/include/lldb/DataFormatters/FormattersHelpers.h b/include/lldb/DataFormatters/FormattersHelpers.h new file mode 100644 index 000000000..14ba5e48f --- /dev/null +++ b/include/lldb/DataFormatters/FormattersHelpers.h @@ -0,0 +1,194 @@ +//===-- FormattersHelpers.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_FormattersHelpers_h_ +#define lldb_FormattersHelpers_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" + +#include "lldb/DataFormatters/TypeCategory.h" +#include "lldb/DataFormatters/TypeFormat.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/DataFormatters/TypeSynthetic.h" + +namespace lldb_private { +namespace formatters { +void AddFormat(TypeCategoryImpl::SharedPointer category_sp, lldb::Format format, + ConstString type_name, TypeFormatImpl::Flags flags, + bool regex = false); + +void AddSummary(TypeCategoryImpl::SharedPointer category_sp, + lldb::TypeSummaryImplSP summary_sp, ConstString type_name, + bool regex = false); + +void AddStringSummary(TypeCategoryImpl::SharedPointer category_sp, + const char *string, ConstString type_name, + TypeSummaryImpl::Flags flags, bool regex = false); + +void AddOneLineSummary(TypeCategoryImpl::SharedPointer category_sp, + ConstString type_name, TypeSummaryImpl::Flags flags, + bool regex = false); + +#ifndef LLDB_DISABLE_PYTHON +void AddCXXSummary(TypeCategoryImpl::SharedPointer category_sp, + CXXFunctionSummaryFormat::Callback funct, + const char *description, ConstString type_name, + TypeSummaryImpl::Flags flags, bool regex = false); + +void AddCXXSynthetic(TypeCategoryImpl::SharedPointer category_sp, + CXXSyntheticChildren::CreateFrontEndCallback generator, + const char *description, ConstString type_name, + ScriptedSyntheticChildren::Flags flags, + bool regex = false); + +void AddFilter(TypeCategoryImpl::SharedPointer category_sp, + std::vector children, const char *description, + ConstString type_name, ScriptedSyntheticChildren::Flags flags, + bool regex = false); +#endif + +size_t ExtractIndexFromString(const char *item_name); + +lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj); + +time_t GetOSXEpoch(); + +struct InferiorSizedWord { + + InferiorSizedWord(const InferiorSizedWord &word) : ptr_size(word.ptr_size) { + if (ptr_size == 4) + thirty_two = word.thirty_two; + else + sixty_four = word.sixty_four; + } + + InferiorSizedWord operator=(const InferiorSizedWord &word) { + ptr_size = word.ptr_size; + if (ptr_size == 4) + thirty_two = word.thirty_two; + else + sixty_four = word.sixty_four; + return *this; + } + + InferiorSizedWord(uint64_t val, Process &process) + : ptr_size(process.GetAddressByteSize()) { + if (ptr_size == 4) + thirty_two = (uint32_t)val; + else if (ptr_size == 8) + sixty_four = val; + else + assert(false && "new pointer size is unknown"); + } + + bool IsNegative() const { + if (ptr_size == 4) + return ((int32_t)thirty_two) < 0; + else + return ((int64_t)sixty_four) < 0; + } + + bool IsZero() const { + if (ptr_size == 4) + return thirty_two == 0; + else + return sixty_four == 0; + } + + static InferiorSizedWord GetMaximum(Process &process) { + if (process.GetAddressByteSize() == 4) + return InferiorSizedWord(UINT32_MAX, 4); + else + return InferiorSizedWord(UINT64_MAX, 8); + } + + InferiorSizedWord operator>>(int rhs) const { + if (ptr_size == 4) + return InferiorSizedWord(thirty_two >> rhs, 4); + return InferiorSizedWord(sixty_four >> rhs, 8); + } + + InferiorSizedWord operator<<(int rhs) const { + if (ptr_size == 4) + return InferiorSizedWord(thirty_two << rhs, 4); + return InferiorSizedWord(sixty_four << rhs, 8); + } + + InferiorSizedWord operator&(const InferiorSizedWord &word) const { + if (ptr_size != word.ptr_size) + return InferiorSizedWord(0, ptr_size); + if (ptr_size == 4) + return InferiorSizedWord(thirty_two & word.thirty_two, 4); + return InferiorSizedWord(sixty_four & word.sixty_four, 8); + } + + InferiorSizedWord operator&(int x) const { + if (ptr_size == 4) + return InferiorSizedWord(thirty_two & x, 4); + return InferiorSizedWord(sixty_four & x, 8); + } + + size_t GetBitSize() const { return ptr_size << 3; } + + size_t GetByteSize() const { return ptr_size; } + + uint64_t GetValue() const { + if (ptr_size == 4) + return (uint64_t)thirty_two; + return sixty_four; + } + + InferiorSizedWord SignExtend() const { + if (ptr_size == 4) + return InferiorSizedWord((int32_t)thirty_two, 4); + return InferiorSizedWord((int64_t)sixty_four, 8); + } + + uint8_t *CopyToBuffer(uint8_t *buffer) const { + if (ptr_size == 4) { + memcpy(buffer, &thirty_two, 4); + return buffer + 4; + } else { + memcpy(buffer, &sixty_four, 8); + return buffer + 8; + } + } + + DataExtractor + GetAsData(lldb::ByteOrder byte_order = lldb::eByteOrderInvalid) const { + if (ptr_size == 4) + return DataExtractor(&thirty_two, 4, byte_order, 4); + else + return DataExtractor(&sixty_four, 8, byte_order, 8); + } + +private: + InferiorSizedWord(uint64_t val, size_t psz) : ptr_size(psz) { + if (ptr_size == 4) + thirty_two = (uint32_t)val; + else + sixty_four = val; + } + + size_t ptr_size; + union { + uint32_t thirty_two; + uint64_t sixty_four; + }; +}; +} // namespace formatters +} // namespace lldb_private + +#endif // lldb_FormattersHelpers_h_ diff --git a/include/lldb/DataFormatters/LanguageCategory.h b/include/lldb/DataFormatters/LanguageCategory.h new file mode 100644 index 000000000..e94429407 --- /dev/null +++ b/include/lldb/DataFormatters/LanguageCategory.h @@ -0,0 +1,80 @@ +//===-- LanguageCategory.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_LanguageCategory_h_ +#define lldb_LanguageCategory_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes +// Project includes +#include "lldb/DataFormatters/FormatCache.h" +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/lldb-public.h" + +#include + +namespace lldb_private { + +class LanguageCategory { +public: + typedef std::unique_ptr UniquePointer; + + LanguageCategory(lldb::LanguageType lang_type); + + bool Get(FormattersMatchData &match_data, lldb::TypeFormatImplSP &format_sp); + + bool Get(FormattersMatchData &match_data, lldb::TypeSummaryImplSP &format_sp); + + bool Get(FormattersMatchData &match_data, + lldb::SyntheticChildrenSP &format_sp); + + bool Get(FormattersMatchData &match_data, + lldb::TypeValidatorImplSP &format_sp); + + bool GetHardcoded(FormatManager &fmt_mgr, FormattersMatchData &match_data, + lldb::TypeFormatImplSP &format_sp); + + bool GetHardcoded(FormatManager &fmt_mgr, FormattersMatchData &match_data, + lldb::TypeSummaryImplSP &format_sp); + + bool GetHardcoded(FormatManager &fmt_mgr, FormattersMatchData &match_data, + lldb::SyntheticChildrenSP &format_sp); + + bool GetHardcoded(FormatManager &fmt_mgr, FormattersMatchData &match_data, + lldb::TypeValidatorImplSP &format_sp); + + lldb::TypeCategoryImplSP GetCategory() const; + + FormatCache &GetFormatCache(); + + void Enable(); + + void Disable(); + + bool IsEnabled(); + +private: + lldb::TypeCategoryImplSP m_category_sp; + + HardcodedFormatters::HardcodedFormatFinder m_hardcoded_formats; + HardcodedFormatters::HardcodedSummaryFinder m_hardcoded_summaries; + HardcodedFormatters::HardcodedSyntheticFinder m_hardcoded_synthetics; + HardcodedFormatters::HardcodedValidatorFinder m_hardcoded_validators; + + lldb_private::FormatCache m_format_cache; + + bool m_enabled; +}; + +} // namespace lldb_private + +#endif // lldb_LanguageCategory_h_ diff --git a/include/lldb/DataFormatters/StringPrinter.h b/include/lldb/DataFormatters/StringPrinter.h new file mode 100644 index 000000000..8d4a099fb --- /dev/null +++ b/include/lldb/DataFormatters/StringPrinter.h @@ -0,0 +1,348 @@ +//===-- StringPrinter.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_StringPrinter_h_ +#define liblldb_StringPrinter_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-forward.h" + +#include "lldb/Utility/DataExtractor.h" + +namespace lldb_private { +namespace formatters { +class StringPrinter { +public: + enum class StringElementType { ASCII, UTF8, UTF16, UTF32 }; + + enum class GetPrintableElementType { ASCII, UTF8 }; + + class ReadStringAndDumpToStreamOptions { + public: + ReadStringAndDumpToStreamOptions() + : m_location(0), m_process_sp(), m_stream(nullptr), m_prefix_token(), + m_suffix_token(), m_quote('"'), m_source_size(0), + m_needs_zero_termination(true), m_escape_non_printables(true), + m_ignore_max_length(false), m_zero_is_terminator(true), + m_language_type(lldb::eLanguageTypeUnknown) {} + + ReadStringAndDumpToStreamOptions(ValueObject &valobj); + + ReadStringAndDumpToStreamOptions &SetLocation(uint64_t l) { + m_location = l; + return *this; + } + + uint64_t GetLocation() const { return m_location; } + + ReadStringAndDumpToStreamOptions &SetProcessSP(lldb::ProcessSP p) { + m_process_sp = p; + return *this; + } + + lldb::ProcessSP GetProcessSP() const { return m_process_sp; } + + ReadStringAndDumpToStreamOptions &SetStream(Stream *s) { + m_stream = s; + return *this; + } + + Stream *GetStream() const { return m_stream; } + + ReadStringAndDumpToStreamOptions &SetPrefixToken(const std::string &p) { + m_prefix_token = p; + return *this; + } + + ReadStringAndDumpToStreamOptions &SetPrefixToken(std::nullptr_t) { + m_prefix_token.clear(); + return *this; + } + + const char *GetPrefixToken() const { return m_prefix_token.c_str(); } + + ReadStringAndDumpToStreamOptions &SetSuffixToken(const std::string &p) { + m_suffix_token = p; + return *this; + } + + ReadStringAndDumpToStreamOptions &SetSuffixToken(std::nullptr_t) { + m_suffix_token.clear(); + return *this; + } + + const char *GetSuffixToken() const { return m_suffix_token.c_str(); } + + ReadStringAndDumpToStreamOptions &SetQuote(char q) { + m_quote = q; + return *this; + } + + char GetQuote() const { return m_quote; } + + ReadStringAndDumpToStreamOptions &SetSourceSize(uint32_t s) { + m_source_size = s; + return *this; + } + + uint32_t GetSourceSize() const { return m_source_size; } + + ReadStringAndDumpToStreamOptions &SetNeedsZeroTermination(bool z) { + m_needs_zero_termination = z; + return *this; + } + + bool GetNeedsZeroTermination() const { return m_needs_zero_termination; } + + ReadStringAndDumpToStreamOptions &SetBinaryZeroIsTerminator(bool e) { + m_zero_is_terminator = e; + return *this; + } + + bool GetBinaryZeroIsTerminator() const { return m_zero_is_terminator; } + + ReadStringAndDumpToStreamOptions &SetEscapeNonPrintables(bool e) { + m_escape_non_printables = e; + return *this; + } + + bool GetEscapeNonPrintables() const { return m_escape_non_printables; } + + ReadStringAndDumpToStreamOptions &SetIgnoreMaxLength(bool e) { + m_ignore_max_length = e; + return *this; + } + + bool GetIgnoreMaxLength() const { return m_ignore_max_length; } + + ReadStringAndDumpToStreamOptions &SetLanguage(lldb::LanguageType l) { + m_language_type = l; + return *this; + } + + lldb::LanguageType GetLanguage() const + + { + return m_language_type; + } + + private: + uint64_t m_location; + lldb::ProcessSP m_process_sp; + Stream *m_stream; + std::string m_prefix_token; + std::string m_suffix_token; + char m_quote; + uint32_t m_source_size; + bool m_needs_zero_termination; + bool m_escape_non_printables; + bool m_ignore_max_length; + bool m_zero_is_terminator; + lldb::LanguageType m_language_type; + }; + + class ReadBufferAndDumpToStreamOptions { + public: + ReadBufferAndDumpToStreamOptions() + : m_data(), m_stream(nullptr), m_prefix_token(), m_suffix_token(), + m_quote('"'), m_source_size(0), m_escape_non_printables(true), + m_zero_is_terminator(true), m_is_truncated(false), + m_language_type(lldb::eLanguageTypeUnknown) {} + + ReadBufferAndDumpToStreamOptions(ValueObject &valobj); + + ReadBufferAndDumpToStreamOptions( + const ReadStringAndDumpToStreamOptions &options); + + ReadBufferAndDumpToStreamOptions &SetData(DataExtractor d) { + m_data = d; + return *this; + } + + lldb_private::DataExtractor GetData() const { return m_data; } + + ReadBufferAndDumpToStreamOptions &SetStream(Stream *s) { + m_stream = s; + return *this; + } + + Stream *GetStream() const { return m_stream; } + + ReadBufferAndDumpToStreamOptions &SetPrefixToken(const std::string &p) { + m_prefix_token = p; + return *this; + } + + ReadBufferAndDumpToStreamOptions &SetPrefixToken(std::nullptr_t) { + m_prefix_token.clear(); + return *this; + } + + const char *GetPrefixToken() const { return m_prefix_token.c_str(); } + + ReadBufferAndDumpToStreamOptions &SetSuffixToken(const std::string &p) { + m_suffix_token = p; + return *this; + } + + ReadBufferAndDumpToStreamOptions &SetSuffixToken(std::nullptr_t) { + m_suffix_token.clear(); + return *this; + } + + const char *GetSuffixToken() const { return m_suffix_token.c_str(); } + + ReadBufferAndDumpToStreamOptions &SetQuote(char q) { + m_quote = q; + return *this; + } + + char GetQuote() const { return m_quote; } + + ReadBufferAndDumpToStreamOptions &SetSourceSize(uint32_t s) { + m_source_size = s; + return *this; + } + + uint32_t GetSourceSize() const { return m_source_size; } + + ReadBufferAndDumpToStreamOptions &SetEscapeNonPrintables(bool e) { + m_escape_non_printables = e; + return *this; + } + + bool GetEscapeNonPrintables() const { return m_escape_non_printables; } + + ReadBufferAndDumpToStreamOptions &SetBinaryZeroIsTerminator(bool e) { + m_zero_is_terminator = e; + return *this; + } + + bool GetBinaryZeroIsTerminator() const { return m_zero_is_terminator; } + + ReadBufferAndDumpToStreamOptions &SetIsTruncated(bool t) { + m_is_truncated = t; + return *this; + } + + bool GetIsTruncated() const { return m_is_truncated; } + + ReadBufferAndDumpToStreamOptions &SetLanguage(lldb::LanguageType l) { + m_language_type = l; + return *this; + } + + lldb::LanguageType GetLanguage() const + + { + return m_language_type; + } + + private: + DataExtractor m_data; + Stream *m_stream; + std::string m_prefix_token; + std::string m_suffix_token; + char m_quote; + uint32_t m_source_size; + bool m_escape_non_printables; + bool m_zero_is_terminator; + bool m_is_truncated; + lldb::LanguageType m_language_type; + }; + + // I can't use a std::unique_ptr for this because the Deleter is a template + // argument there + // and I want the same type to represent both pointers I want to free and + // pointers I don't need + // to free - which is what this class essentially is + // It's very specialized to the needs of this file, and not suggested for + // general use + template + struct StringPrinterBufferPointer { + public: + typedef std::function Deleter; + + StringPrinterBufferPointer(std::nullptr_t ptr) + : m_data(nullptr), m_size(0), m_deleter() {} + + StringPrinterBufferPointer(const T *bytes, S size, + Deleter deleter = nullptr) + : m_data(bytes), m_size(size), m_deleter(deleter) {} + + StringPrinterBufferPointer(const U *bytes, S size, + Deleter deleter = nullptr) + : m_data(reinterpret_cast(bytes)), m_size(size), + m_deleter(deleter) {} + + StringPrinterBufferPointer(StringPrinterBufferPointer &&rhs) + : m_data(rhs.m_data), m_size(rhs.m_size), m_deleter(rhs.m_deleter) { + rhs.m_data = nullptr; + } + + StringPrinterBufferPointer(const StringPrinterBufferPointer &rhs) + : m_data(rhs.m_data), m_size(rhs.m_size), m_deleter(rhs.m_deleter) { + rhs.m_data = nullptr; // this is why m_data has to be mutable + } + + ~StringPrinterBufferPointer() { + if (m_data && m_deleter) + m_deleter(m_data); + m_data = nullptr; + } + + const T *GetBytes() const { return m_data; } + + const S GetSize() const { return m_size; } + + StringPrinterBufferPointer & + operator=(const StringPrinterBufferPointer &rhs) { + if (m_data && m_deleter) + m_deleter(m_data); + m_data = rhs.m_data; + m_size = rhs.m_size; + m_deleter = rhs.m_deleter; + rhs.m_data = nullptr; + return *this; + } + + private: + mutable const T *m_data; + size_t m_size; + Deleter m_deleter; + }; + + typedef std::function(uint8_t *, uint8_t *, uint8_t *&)> + EscapingHelper; + typedef std::function + EscapingHelperGenerator; + + static EscapingHelper + GetDefaultEscapingHelper(GetPrintableElementType elem_type); + + template + static bool + ReadStringAndDumpToStream(const ReadStringAndDumpToStreamOptions &options); + + template + static bool + ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options); +}; + +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_StringPrinter_h_ diff --git a/include/lldb/DataFormatters/TypeCategory.h b/include/lldb/DataFormatters/TypeCategory.h new file mode 100644 index 000000000..0a5b09baa --- /dev/null +++ b/include/lldb/DataFormatters/TypeCategory.h @@ -0,0 +1,452 @@ +//===-- TypeCategory.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_TypeCategory_h_ +#define lldb_TypeCategory_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/FormattersContainer.h" + +namespace lldb_private { + +template class FormatterContainerPair { +public: + typedef FormattersContainer ExactMatchContainer; + typedef FormattersContainer + RegexMatchContainer; + + typedef typename ExactMatchContainer::MapType ExactMatchMap; + typedef typename RegexMatchContainer::MapType RegexMatchMap; + + typedef typename ExactMatchContainer::MapValueType MapValueType; + + typedef typename ExactMatchContainer::SharedPointer ExactMatchContainerSP; + typedef typename RegexMatchContainer::SharedPointer RegexMatchContainerSP; + + typedef + typename ExactMatchContainer::ForEachCallback ExactMatchForEachCallback; + typedef + typename RegexMatchContainer::ForEachCallback RegexMatchForEachCallback; + + FormatterContainerPair(const char *exact_name, const char *regex_name, + IFormatChangeListener *clist) + : m_exact_sp(new ExactMatchContainer(std::string(exact_name), clist)), + m_regex_sp(new RegexMatchContainer(std::string(regex_name), clist)) {} + + ~FormatterContainerPair() = default; + + ExactMatchContainerSP GetExactMatch() const { return m_exact_sp; } + + RegexMatchContainerSP GetRegexMatch() const { return m_regex_sp; } + + uint32_t GetCount() { + return GetExactMatch()->GetCount() + GetRegexMatch()->GetCount(); + } + +private: + ExactMatchContainerSP m_exact_sp; + RegexMatchContainerSP m_regex_sp; +}; + +class TypeCategoryImpl { +private: + typedef FormatterContainerPair FormatContainer; + typedef FormatterContainerPair SummaryContainer; + typedef FormatterContainerPair FilterContainer; + typedef FormatterContainerPair ValidatorContainer; + +#ifndef LLDB_DISABLE_PYTHON + typedef FormatterContainerPair SynthContainer; +#endif // LLDB_DISABLE_PYTHON + +public: + typedef uint16_t FormatCategoryItems; + static const uint16_t ALL_ITEM_TYPES = UINT16_MAX; + + typedef FormatContainer::ExactMatchContainerSP FormatContainerSP; + typedef FormatContainer::RegexMatchContainerSP RegexFormatContainerSP; + + typedef SummaryContainer::ExactMatchContainerSP SummaryContainerSP; + typedef SummaryContainer::RegexMatchContainerSP RegexSummaryContainerSP; + + typedef FilterContainer::ExactMatchContainerSP FilterContainerSP; + typedef FilterContainer::RegexMatchContainerSP RegexFilterContainerSP; +#ifndef LLDB_DISABLE_PYTHON + typedef SynthContainer::ExactMatchContainerSP SynthContainerSP; + typedef SynthContainer::RegexMatchContainerSP RegexSynthContainerSP; +#endif // LLDB_DISABLE_PYTHON + + typedef ValidatorContainer::ExactMatchContainerSP ValidatorContainerSP; + typedef ValidatorContainer::RegexMatchContainerSP RegexValidatorContainerSP; + + template class ForEachCallbacks { + public: + ForEachCallbacks() = default; + ~ForEachCallbacks() = default; + + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetExact(FormatContainer::ExactMatchForEachCallback callback) { + m_format_exact = callback; + return *this; + } + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetWithRegex(FormatContainer::RegexMatchForEachCallback callback) { + m_format_regex = callback; + return *this; + } + + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetExact(SummaryContainer::ExactMatchForEachCallback callback) { + m_summary_exact = callback; + return *this; + } + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetWithRegex(SummaryContainer::RegexMatchForEachCallback callback) { + m_summary_regex = callback; + return *this; + } + + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetExact(FilterContainer::ExactMatchForEachCallback callback) { + m_filter_exact = callback; + return *this; + } + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetWithRegex(FilterContainer::RegexMatchForEachCallback callback) { + m_filter_regex = callback; + return *this; + } + +#ifndef LLDB_DISABLE_PYTHON + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetExact(SynthContainer::ExactMatchForEachCallback callback) { + m_synth_exact = callback; + return *this; + } + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetWithRegex(SynthContainer::RegexMatchForEachCallback callback) { + m_synth_regex = callback; + return *this; + } +#endif // LLDB_DISABLE_PYTHON + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetExact(ValidatorContainer::ExactMatchForEachCallback callback) { + m_validator_exact = callback; + return *this; + } + template + typename std::enable_if::value, ForEachCallbacks &>::type + SetWithRegex(ValidatorContainer::RegexMatchForEachCallback callback) { + m_validator_regex = callback; + return *this; + } + + FormatContainer::ExactMatchForEachCallback GetFormatExactCallback() const { + return m_format_exact; + } + FormatContainer::RegexMatchForEachCallback GetFormatRegexCallback() const { + return m_format_regex; + } + + SummaryContainer::ExactMatchForEachCallback + GetSummaryExactCallback() const { + return m_summary_exact; + } + SummaryContainer::RegexMatchForEachCallback + GetSummaryRegexCallback() const { + return m_summary_regex; + } + + FilterContainer::ExactMatchForEachCallback GetFilterExactCallback() const { + return m_filter_exact; + } + FilterContainer::RegexMatchForEachCallback GetFilterRegexCallback() const { + return m_filter_regex; + } + +#ifndef LLDB_DISABLE_PYTHON + SynthContainer::ExactMatchForEachCallback GetSynthExactCallback() const { + return m_synth_exact; + } + SynthContainer::RegexMatchForEachCallback GetSynthRegexCallback() const { + return m_synth_regex; + } +#endif // LLDB_DISABLE_PYTHON + + ValidatorContainer::ExactMatchForEachCallback + GetValidatorExactCallback() const { + return m_validator_exact; + } + ValidatorContainer::RegexMatchForEachCallback + GetValidatorRegexCallback() const { + return m_validator_regex; + } + + private: + FormatContainer::ExactMatchForEachCallback m_format_exact; + FormatContainer::RegexMatchForEachCallback m_format_regex; + + SummaryContainer::ExactMatchForEachCallback m_summary_exact; + SummaryContainer::RegexMatchForEachCallback m_summary_regex; + + FilterContainer::ExactMatchForEachCallback m_filter_exact; + FilterContainer::RegexMatchForEachCallback m_filter_regex; + +#ifndef LLDB_DISABLE_PYTHON + SynthContainer::ExactMatchForEachCallback m_synth_exact; + SynthContainer::RegexMatchForEachCallback m_synth_regex; +#endif // LLDB_DISABLE_PYTHON + + ValidatorContainer::ExactMatchForEachCallback m_validator_exact; + ValidatorContainer::RegexMatchForEachCallback m_validator_regex; + }; + + TypeCategoryImpl(IFormatChangeListener *clist, ConstString name, + std::initializer_list langs = {}); + + template void ForEach(const ForEachCallbacks &foreach) { + GetTypeFormatsContainer()->ForEach(foreach.GetFormatExactCallback()); + GetRegexTypeFormatsContainer()->ForEach(foreach.GetFormatRegexCallback()); + + GetTypeSummariesContainer()->ForEach(foreach.GetSummaryExactCallback()); + GetRegexTypeSummariesContainer()->ForEach( + foreach.GetSummaryRegexCallback()); + + GetTypeFiltersContainer()->ForEach(foreach.GetFilterExactCallback()); + GetRegexTypeFiltersContainer()->ForEach(foreach.GetFilterRegexCallback()); + +#ifndef LLDB_DISABLE_PYTHON + GetTypeSyntheticsContainer()->ForEach(foreach.GetSynthExactCallback()); + GetRegexTypeSyntheticsContainer()->ForEach(foreach.GetSynthRegexCallback()); +#endif // LLDB_DISABLE_PYTHON + + GetTypeValidatorsContainer()->ForEach(foreach.GetValidatorExactCallback()); + GetRegexTypeValidatorsContainer()->ForEach( + foreach.GetValidatorRegexCallback()); + } + + FormatContainerSP GetTypeFormatsContainer() { + return m_format_cont.GetExactMatch(); + } + + RegexFormatContainerSP GetRegexTypeFormatsContainer() { + return m_format_cont.GetRegexMatch(); + } + + FormatContainer &GetFormatContainer() { return m_format_cont; } + + SummaryContainerSP GetTypeSummariesContainer() { + return m_summary_cont.GetExactMatch(); + } + + RegexSummaryContainerSP GetRegexTypeSummariesContainer() { + return m_summary_cont.GetRegexMatch(); + } + + SummaryContainer &GetSummaryContainer() { return m_summary_cont; } + + FilterContainerSP GetTypeFiltersContainer() { + return m_filter_cont.GetExactMatch(); + } + + RegexFilterContainerSP GetRegexTypeFiltersContainer() { + return m_filter_cont.GetRegexMatch(); + } + + FilterContainer &GetFilterContainer() { return m_filter_cont; } + + FormatContainer::MapValueType + GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp); + + SummaryContainer::MapValueType + GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp); + + FilterContainer::MapValueType + GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp); + +#ifndef LLDB_DISABLE_PYTHON + SynthContainer::MapValueType + GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp); +#endif + + ValidatorContainer::MapValueType + GetValidatorForType(lldb::TypeNameSpecifierImplSP type_sp); + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierForFormatAtIndex(size_t index); + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierForSummaryAtIndex(size_t index); + + FormatContainer::MapValueType GetFormatAtIndex(size_t index); + + SummaryContainer::MapValueType GetSummaryAtIndex(size_t index); + + FilterContainer::MapValueType GetFilterAtIndex(size_t index); + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierForFilterAtIndex(size_t index); + +#ifndef LLDB_DISABLE_PYTHON + SynthContainerSP GetTypeSyntheticsContainer() { + return m_synth_cont.GetExactMatch(); + } + + RegexSynthContainerSP GetRegexTypeSyntheticsContainer() { + return m_synth_cont.GetRegexMatch(); + } + + SynthContainer &GetSyntheticsContainer() { return m_synth_cont; } + + SynthContainer::MapValueType GetSyntheticAtIndex(size_t index); + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierForSyntheticAtIndex(size_t index); +#endif // LLDB_DISABLE_PYTHON + + ValidatorContainerSP GetTypeValidatorsContainer() { + return m_validator_cont.GetExactMatch(); + } + + RegexValidatorContainerSP GetRegexTypeValidatorsContainer() { + return m_validator_cont.GetRegexMatch(); + } + + ValidatorContainer::MapValueType GetValidatorAtIndex(size_t index); + + lldb::TypeNameSpecifierImplSP + GetTypeNameSpecifierForValidatorAtIndex(size_t index); + + bool IsEnabled() const { return m_enabled; } + + uint32_t GetEnabledPosition() { + if (m_enabled == false) + return UINT32_MAX; + else + return m_enabled_position; + } + + bool Get(ValueObject &valobj, const FormattersMatchVector &candidates, + lldb::TypeFormatImplSP &entry, uint32_t *reason = nullptr); + + bool Get(ValueObject &valobj, const FormattersMatchVector &candidates, + lldb::TypeSummaryImplSP &entry, uint32_t *reason = nullptr); + + bool Get(ValueObject &valobj, const FormattersMatchVector &candidates, + lldb::SyntheticChildrenSP &entry, uint32_t *reason = nullptr); + + bool Get(ValueObject &valobj, const FormattersMatchVector &candidates, + lldb::TypeValidatorImplSP &entry, uint32_t *reason = nullptr); + + void Clear(FormatCategoryItems items = ALL_ITEM_TYPES); + + bool Delete(ConstString name, FormatCategoryItems items = ALL_ITEM_TYPES); + + uint32_t GetCount(FormatCategoryItems items = ALL_ITEM_TYPES); + + const char *GetName() { return m_name.GetCString(); } + + size_t GetNumLanguages(); + + lldb::LanguageType GetLanguageAtIndex(size_t idx); + + void AddLanguage(lldb::LanguageType lang); + + bool HasLanguage(lldb::LanguageType lang); + + std::string GetDescription(); + + bool AnyMatches(ConstString type_name, + FormatCategoryItems items = ALL_ITEM_TYPES, + bool only_enabled = true, + const char **matching_category = nullptr, + FormatCategoryItems *matching_type = nullptr); + + typedef std::shared_ptr SharedPointer; + +private: + FormatContainer m_format_cont; + SummaryContainer m_summary_cont; + FilterContainer m_filter_cont; +#ifndef LLDB_DISABLE_PYTHON + SynthContainer m_synth_cont; +#endif // LLDB_DISABLE_PYTHON + ValidatorContainer m_validator_cont; + + bool m_enabled; + + IFormatChangeListener *m_change_listener; + + std::recursive_mutex m_mutex; + + ConstString m_name; + + std::vector m_languages; + + uint32_t m_enabled_position; + + void Enable(bool value, uint32_t position); + + void Disable() { Enable(false, UINT32_MAX); } + + bool IsApplicable(ValueObject &valobj); + + uint32_t GetLastEnabledPosition() { return m_enabled_position; } + + void SetEnabledPosition(uint32_t p) { m_enabled_position = p; } + + friend class FormatManager; + friend class LanguageCategory; + friend class TypeCategoryMap; + + friend class FormattersContainer; + friend class FormattersContainer; + + friend class FormattersContainer; + friend class FormattersContainer; + + friend class FormattersContainer; + friend class FormattersContainer; + +#ifndef LLDB_DISABLE_PYTHON + friend class FormattersContainer; + friend class FormattersContainer; +#endif // LLDB_DISABLE_PYTHON + + friend class FormattersContainer; + friend class FormattersContainer; +}; + +} // namespace lldb_private + +#endif // lldb_TypeCategory_h_ diff --git a/include/lldb/DataFormatters/TypeCategoryMap.h b/include/lldb/DataFormatters/TypeCategoryMap.h new file mode 100644 index 000000000..f767c985f --- /dev/null +++ b/include/lldb/DataFormatters/TypeCategoryMap.h @@ -0,0 +1,125 @@ +//===-- TypeCategoryMap.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_TypeCategoryMap_h_ +#define lldb_TypeCategoryMap_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +#include "lldb/DataFormatters/FormattersContainer.h" +#include "lldb/DataFormatters/TypeCategory.h" + +namespace lldb_private { +class TypeCategoryMap { +private: + typedef ConstString KeyType; + typedef TypeCategoryImpl ValueType; + typedef ValueType::SharedPointer ValueSP; + typedef std::list ActiveCategoriesList; + typedef ActiveCategoriesList::iterator ActiveCategoriesIterator; + +public: + typedef std::map MapType; + typedef MapType::iterator MapIterator; + typedef std::function ForEachCallback; + + typedef uint32_t Position; + + static const Position First = 0; + static const Position Default = 1; + static const Position Last = UINT32_MAX; + + TypeCategoryMap(IFormatChangeListener *lst); + + void Add(KeyType name, const ValueSP &entry); + + bool Delete(KeyType name); + + bool Enable(KeyType category_name, Position pos = Default); + + bool Disable(KeyType category_name); + + bool Enable(ValueSP category, Position pos = Default); + + bool Disable(ValueSP category); + + void EnableAllCategories(); + + void DisableAllCategories(); + + void Clear(); + + bool Get(KeyType name, ValueSP &entry); + + bool Get(uint32_t pos, ValueSP &entry); + + void ForEach(ForEachCallback callback); + + lldb::TypeCategoryImplSP GetAtIndex(uint32_t); + + bool + AnyMatches(ConstString type_name, + TypeCategoryImpl::FormatCategoryItems items = + TypeCategoryImpl::ALL_ITEM_TYPES, + bool only_enabled = true, const char **matching_category = nullptr, + TypeCategoryImpl::FormatCategoryItems *matching_type = nullptr); + + uint32_t GetCount() { return m_map.size(); } + + lldb::TypeFormatImplSP GetFormat(FormattersMatchData &match_data); + + lldb::TypeSummaryImplSP GetSummaryFormat(FormattersMatchData &match_data); + +#ifndef LLDB_DISABLE_PYTHON + lldb::SyntheticChildrenSP + GetSyntheticChildren(FormattersMatchData &match_data); +#endif + + lldb::TypeValidatorImplSP GetValidator(FormattersMatchData &match_data); + +private: + class delete_matching_categories { + lldb::TypeCategoryImplSP ptr; + + public: + delete_matching_categories(lldb::TypeCategoryImplSP p) : ptr(p) {} + + bool operator()(const lldb::TypeCategoryImplSP &other) { + return ptr.get() == other.get(); + } + }; + + std::recursive_mutex m_map_mutex; + IFormatChangeListener *listener; + + MapType m_map; + ActiveCategoriesList m_active_categories; + + MapType &map() { return m_map; } + + ActiveCategoriesList &active_list() { return m_active_categories; } + + std::recursive_mutex &mutex() { return m_map_mutex; } + + friend class FormattersContainer; + friend class FormatManager; +}; +} // namespace lldb_private + +#endif // lldb_TypeCategoryMap_h_ diff --git a/include/lldb/DataFormatters/TypeFormat.h b/include/lldb/DataFormatters/TypeFormat.h new file mode 100644 index 000000000..8cfe021da --- /dev/null +++ b/include/lldb/DataFormatters/TypeFormat.h @@ -0,0 +1,223 @@ +//===-- TypeFormat.h ----------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_TypeFormat_h_ +#define lldb_TypeFormat_h_ + +// C Includes + +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes + +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +#include "lldb/Core/ValueObject.h" + +namespace lldb_private { +class TypeFormatImpl { +public: + class Flags { + public: + Flags() : m_flags(lldb::eTypeOptionCascade) {} + + Flags(const Flags &other) : m_flags(other.m_flags) {} + + Flags(uint32_t value) : m_flags(value) {} + + Flags &operator=(const Flags &rhs) { + if (&rhs != this) + m_flags = rhs.m_flags; + + return *this; + } + + Flags &operator=(const uint32_t &rhs) { + m_flags = rhs; + return *this; + } + + Flags &Clear() { + m_flags = 0; + return *this; + } + + bool GetCascades() const { + return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; + } + + Flags &SetCascades(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionCascade; + else + m_flags &= ~lldb::eTypeOptionCascade; + return *this; + } + + bool GetSkipPointers() const { + return (m_flags & lldb::eTypeOptionSkipPointers) == + lldb::eTypeOptionSkipPointers; + } + + Flags &SetSkipPointers(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipPointers; + else + m_flags &= ~lldb::eTypeOptionSkipPointers; + return *this; + } + + bool GetSkipReferences() const { + return (m_flags & lldb::eTypeOptionSkipReferences) == + lldb::eTypeOptionSkipReferences; + } + + Flags &SetSkipReferences(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipReferences; + else + m_flags &= ~lldb::eTypeOptionSkipReferences; + return *this; + } + + bool GetNonCacheable() const { + return (m_flags & lldb::eTypeOptionNonCacheable) == + lldb::eTypeOptionNonCacheable; + } + + Flags &SetNonCacheable(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionNonCacheable; + else + m_flags &= ~lldb::eTypeOptionNonCacheable; + return *this; + } + + uint32_t GetValue() { return m_flags; } + + void SetValue(uint32_t value) { m_flags = value; } + + private: + uint32_t m_flags; + }; + + TypeFormatImpl(const Flags &flags = Flags()); + + typedef std::shared_ptr SharedPointer; + + virtual ~TypeFormatImpl(); + + bool Cascades() const { return m_flags.GetCascades(); } + + bool SkipsPointers() const { return m_flags.GetSkipPointers(); } + + bool SkipsReferences() const { return m_flags.GetSkipReferences(); } + + bool NonCacheable() const { return m_flags.GetNonCacheable(); } + + void SetCascades(bool value) { m_flags.SetCascades(value); } + + void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } + + void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } + + void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } + + uint32_t GetOptions() { return m_flags.GetValue(); } + + void SetOptions(uint32_t value) { m_flags.SetValue(value); } + + uint32_t &GetRevision() { return m_my_revision; } + + enum class Type { eTypeUnknown, eTypeFormat, eTypeEnum }; + + virtual Type GetType() { return Type::eTypeUnknown; } + + // we are using a ValueObject* instead of a ValueObjectSP because we do not + // need to hold on to this for + // extended periods of time and we trust the ValueObject to stay around for as + // long as it is required + // for us to generate its value + virtual bool FormatObject(ValueObject *valobj, std::string &dest) const = 0; + + virtual std::string GetDescription() = 0; + +protected: + Flags m_flags; + uint32_t m_my_revision; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl); +}; + +class TypeFormatImpl_Format : public TypeFormatImpl { +public: + TypeFormatImpl_Format(lldb::Format f = lldb::eFormatInvalid, + const TypeFormatImpl::Flags &flags = Flags()); + + typedef std::shared_ptr SharedPointer; + + ~TypeFormatImpl_Format() override; + + lldb::Format GetFormat() const { return m_format; } + + void SetFormat(lldb::Format fmt) { m_format = fmt; } + + TypeFormatImpl::Type GetType() override { + return TypeFormatImpl::Type::eTypeFormat; + } + + bool FormatObject(ValueObject *valobj, std::string &dest) const override; + + std::string GetDescription() override; + +protected: + lldb::Format m_format; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl_Format); +}; + +class TypeFormatImpl_EnumType : public TypeFormatImpl { +public: + TypeFormatImpl_EnumType(ConstString type_name = ConstString(""), + const TypeFormatImpl::Flags &flags = Flags()); + + typedef std::shared_ptr SharedPointer; + + ~TypeFormatImpl_EnumType() override; + + ConstString GetTypeName() { return m_enum_type; } + + void SetTypeName(ConstString enum_type) { m_enum_type = enum_type; } + + TypeFormatImpl::Type GetType() override { + return TypeFormatImpl::Type::eTypeEnum; + } + + bool FormatObject(ValueObject *valobj, std::string &dest) const override; + + std::string GetDescription() override; + +protected: + ConstString m_enum_type; + mutable std::unordered_map m_types; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl_EnumType); +}; +} // namespace lldb_private + +#endif // lldb_TypeFormat_h_ diff --git a/include/lldb/DataFormatters/TypeSummary.h b/include/lldb/DataFormatters/TypeSummary.h new file mode 100644 index 000000000..1bde565aa --- /dev/null +++ b/include/lldb/DataFormatters/TypeSummary.h @@ -0,0 +1,403 @@ +//===-- TypeSummary.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_TypeSummary_h_ +#define lldb_TypeSummary_h_ + +// C Includes +#include + +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +#include "lldb/Core/FormatEntity.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/StructuredData.h" + +namespace lldb_private { +class TypeSummaryOptions { +public: + TypeSummaryOptions(); + TypeSummaryOptions(const TypeSummaryOptions &rhs); + + ~TypeSummaryOptions() = default; + + TypeSummaryOptions &operator=(const TypeSummaryOptions &rhs); + + lldb::LanguageType GetLanguage() const; + + lldb::TypeSummaryCapping GetCapping() const; + + TypeSummaryOptions &SetLanguage(lldb::LanguageType); + + TypeSummaryOptions &SetCapping(lldb::TypeSummaryCapping); + +private: + lldb::LanguageType m_lang; + lldb::TypeSummaryCapping m_capping; +}; + +class TypeSummaryImpl { +public: + enum class Kind { eSummaryString, eScript, eCallback, eInternal }; + + virtual ~TypeSummaryImpl() = default; + + Kind GetKind() const { return m_kind; } + + class Flags { + public: + Flags() : m_flags(lldb::eTypeOptionCascade) {} + + Flags(const Flags &other) : m_flags(other.m_flags) {} + + Flags(uint32_t value) : m_flags(value) {} + + Flags &operator=(const Flags &rhs) { + if (&rhs != this) + m_flags = rhs.m_flags; + + return *this; + } + + Flags &operator=(const uint32_t &rhs) { + m_flags = rhs; + return *this; + } + + Flags &Clear() { + m_flags = 0; + return *this; + } + + bool GetCascades() const { + return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; + } + + Flags &SetCascades(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionCascade; + else + m_flags &= ~lldb::eTypeOptionCascade; + return *this; + } + + bool GetSkipPointers() const { + return (m_flags & lldb::eTypeOptionSkipPointers) == + lldb::eTypeOptionSkipPointers; + } + + Flags &SetSkipPointers(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipPointers; + else + m_flags &= ~lldb::eTypeOptionSkipPointers; + return *this; + } + + bool GetSkipReferences() const { + return (m_flags & lldb::eTypeOptionSkipReferences) == + lldb::eTypeOptionSkipReferences; + } + + Flags &SetSkipReferences(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipReferences; + else + m_flags &= ~lldb::eTypeOptionSkipReferences; + return *this; + } + + bool GetDontShowChildren() const { + return (m_flags & lldb::eTypeOptionHideChildren) == + lldb::eTypeOptionHideChildren; + } + + Flags &SetDontShowChildren(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionHideChildren; + else + m_flags &= ~lldb::eTypeOptionHideChildren; + return *this; + } + + bool GetHideEmptyAggregates() const { + return (m_flags & lldb::eTypeOptionHideEmptyAggregates) == + lldb::eTypeOptionHideEmptyAggregates; + } + + Flags &SetHideEmptyAggregates(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionHideEmptyAggregates; + else + m_flags &= ~lldb::eTypeOptionHideEmptyAggregates; + return *this; + } + + bool GetDontShowValue() const { + return (m_flags & lldb::eTypeOptionHideValue) == + lldb::eTypeOptionHideValue; + } + + Flags &SetDontShowValue(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionHideValue; + else + m_flags &= ~lldb::eTypeOptionHideValue; + return *this; + } + + bool GetShowMembersOneLiner() const { + return (m_flags & lldb::eTypeOptionShowOneLiner) == + lldb::eTypeOptionShowOneLiner; + } + + Flags &SetShowMembersOneLiner(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionShowOneLiner; + else + m_flags &= ~lldb::eTypeOptionShowOneLiner; + return *this; + } + + bool GetHideItemNames() const { + return (m_flags & lldb::eTypeOptionHideNames) == + lldb::eTypeOptionHideNames; + } + + Flags &SetHideItemNames(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionHideNames; + else + m_flags &= ~lldb::eTypeOptionHideNames; + return *this; + } + + bool GetNonCacheable() const { + return (m_flags & lldb::eTypeOptionNonCacheable) == + lldb::eTypeOptionNonCacheable; + } + + Flags &SetNonCacheable(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionNonCacheable; + else + m_flags &= ~lldb::eTypeOptionNonCacheable; + return *this; + } + + uint32_t GetValue() { return m_flags; } + + void SetValue(uint32_t value) { m_flags = value; } + + private: + uint32_t m_flags; + }; + + bool Cascades() const { return m_flags.GetCascades(); } + + bool SkipsPointers() const { return m_flags.GetSkipPointers(); } + + bool SkipsReferences() const { return m_flags.GetSkipReferences(); } + + bool NonCacheable() const { return m_flags.GetNonCacheable(); } + + virtual bool DoesPrintChildren(ValueObject *valobj) const { + return !m_flags.GetDontShowChildren(); + } + + virtual bool DoesPrintEmptyAggregates() const { + return !m_flags.GetHideEmptyAggregates(); + } + + virtual bool DoesPrintValue(ValueObject *valobj) const { + return !m_flags.GetDontShowValue(); + } + + bool IsOneLiner() const { return m_flags.GetShowMembersOneLiner(); } + + virtual bool HideNames(ValueObject *valobj) const { + return m_flags.GetHideItemNames(); + } + + void SetCascades(bool value) { m_flags.SetCascades(value); } + + void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } + + void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } + + virtual void SetDoesPrintChildren(bool value) { + m_flags.SetDontShowChildren(!value); + } + + virtual void SetDoesPrintValue(bool value) { + m_flags.SetDontShowValue(!value); + } + + void SetIsOneLiner(bool value) { m_flags.SetShowMembersOneLiner(value); } + + virtual void SetHideNames(bool value) { m_flags.SetHideItemNames(value); } + + virtual void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } + + uint32_t GetOptions() { return m_flags.GetValue(); } + + void SetOptions(uint32_t value) { m_flags.SetValue(value); } + + // we are using a ValueObject* instead of a ValueObjectSP because we do not + // need to hold on to this for + // extended periods of time and we trust the ValueObject to stay around for as + // long as it is required + // for us to generate its summary + virtual bool FormatObject(ValueObject *valobj, std::string &dest, + const TypeSummaryOptions &options) = 0; + + virtual std::string GetDescription() = 0; + + uint32_t &GetRevision() { return m_my_revision; } + + typedef std::shared_ptr SharedPointer; + +protected: + uint32_t m_my_revision; + Flags m_flags; + + TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags); + +private: + Kind m_kind; + DISALLOW_COPY_AND_ASSIGN(TypeSummaryImpl); +}; + +// simple string-based summaries, using ${var to show data +struct StringSummaryFormat : public TypeSummaryImpl { + std::string m_format_str; + FormatEntity::Entry m_format; + Status m_error; + + StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f); + + ~StringSummaryFormat() override = default; + + const char *GetSummaryString() const { return m_format_str.c_str(); } + + void SetSummaryString(const char *f); + + bool FormatObject(ValueObject *valobj, std::string &dest, + const TypeSummaryOptions &options) override; + + std::string GetDescription() override; + + static bool classof(const TypeSummaryImpl *S) { + return S->GetKind() == Kind::eSummaryString; + } + +private: + DISALLOW_COPY_AND_ASSIGN(StringSummaryFormat); +}; + +// summaries implemented via a C++ function +struct CXXFunctionSummaryFormat : public TypeSummaryImpl { + // we should convert these to SBValue and SBStream if we ever cross + // the boundary towards the external world + typedef std::function + Callback; + + Callback m_impl; + std::string m_description; + + CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl, + const char *description); + + ~CXXFunctionSummaryFormat() override = default; + + Callback GetBackendFunction() const { return m_impl; } + + const char *GetTextualInfo() const { return m_description.c_str(); } + + void SetBackendFunction(Callback cb_func) { m_impl = cb_func; } + + void SetTextualInfo(const char *descr) { + if (descr) + m_description.assign(descr); + else + m_description.clear(); + } + + bool FormatObject(ValueObject *valobj, std::string &dest, + const TypeSummaryOptions &options) override; + + std::string GetDescription() override; + + static bool classof(const TypeSummaryImpl *S) { + return S->GetKind() == Kind::eCallback; + } + + typedef std::shared_ptr SharedPointer; + +private: + DISALLOW_COPY_AND_ASSIGN(CXXFunctionSummaryFormat); +}; + +// Python-based summaries, running script code to show data +struct ScriptSummaryFormat : public TypeSummaryImpl { + std::string m_function_name; + std::string m_python_script; + StructuredData::ObjectSP m_script_function_sp; + + ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, + const char *function_name, + const char *python_script = nullptr); + + ~ScriptSummaryFormat() override = default; + + const char *GetFunctionName() const { return m_function_name.c_str(); } + + const char *GetPythonScript() const { return m_python_script.c_str(); } + + void SetFunctionName(const char *function_name) { + if (function_name) + m_function_name.assign(function_name); + else + m_function_name.clear(); + m_python_script.clear(); + } + + void SetPythonScript(const char *script) { + if (script) + m_python_script.assign(script); + else + m_python_script.clear(); + } + + bool FormatObject(ValueObject *valobj, std::string &dest, + const TypeSummaryOptions &options) override; + + std::string GetDescription() override; + + static bool classof(const TypeSummaryImpl *S) { + return S->GetKind() == Kind::eScript; + } + + typedef std::shared_ptr SharedPointer; + +private: + DISALLOW_COPY_AND_ASSIGN(ScriptSummaryFormat); +}; +} // namespace lldb_private + +#endif // lldb_TypeSummary_h_ diff --git a/include/lldb/DataFormatters/TypeSynthetic.h b/include/lldb/DataFormatters/TypeSynthetic.h new file mode 100644 index 000000000..59fb6d3fc --- /dev/null +++ b/include/lldb/DataFormatters/TypeSynthetic.h @@ -0,0 +1,453 @@ +//===-- TypeSynthetic.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_TypeSynthetic_h_ +#define lldb_TypeSynthetic_h_ + +// C Includes +#include + +// C++ Includes +#include +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-public.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/Utility/StructuredData.h" + +namespace lldb_private { +class SyntheticChildrenFrontEnd { +protected: + ValueObject &m_backend; + + void SetValid(bool valid) { m_valid = valid; } + + bool IsValid() { return m_valid; } + +public: + SyntheticChildrenFrontEnd(ValueObject &backend) + : m_backend(backend), m_valid(true) {} + + virtual ~SyntheticChildrenFrontEnd() = default; + + virtual size_t CalculateNumChildren() = 0; + + virtual size_t CalculateNumChildren(uint32_t max) { + auto count = CalculateNumChildren(); + return count <= max ? count : max; + } + + virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx) = 0; + + virtual size_t GetIndexOfChildWithName(const ConstString &name) = 0; + + // this function is assumed to always succeed and it if fails, the front-end + // should know to deal + // with it in the correct way (most probably, by refusing to return any + // children) + // the return value of Update() should actually be interpreted as + // "ValueObjectSyntheticFilter cache is good/bad" + // if =true, ValueObjectSyntheticFilter is allowed to use the children it + // fetched previously and cached + // if =false, ValueObjectSyntheticFilter must throw away its cache, and query + // again for children + virtual bool Update() = 0; + + // if this function returns false, then CalculateNumChildren() MUST return 0 + // since UI frontends + // might validly decide not to inquire for children given a false return value + // from this call + // if it returns true, then CalculateNumChildren() can return any number >= 0 + // (0 being valid) + // it should if at all possible be more efficient than CalculateNumChildren() + virtual bool MightHaveChildren() = 0; + + // if this function returns a non-null ValueObject, then the returned + // ValueObject will stand + // for this ValueObject whenever a "value" request is made to this ValueObject + virtual lldb::ValueObjectSP GetSyntheticValue() { return nullptr; } + + // if this function returns a non-empty ConstString, then clients are expected + // to use the return + // as the name of the type of this ValueObject for display purposes + virtual ConstString GetSyntheticTypeName() { return ConstString(); } + + typedef std::shared_ptr SharedPointer; + typedef std::unique_ptr AutoPointer; + +protected: + lldb::ValueObjectSP + CreateValueObjectFromExpression(llvm::StringRef name, + llvm::StringRef expression, + const ExecutionContext &exe_ctx); + + lldb::ValueObjectSP + CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, + const ExecutionContext &exe_ctx, + CompilerType type); + + lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, + const DataExtractor &data, + const ExecutionContext &exe_ctx, + CompilerType type); + +private: + bool m_valid; + DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd); +}; + +class SyntheticValueProviderFrontEnd : public SyntheticChildrenFrontEnd { +public: + SyntheticValueProviderFrontEnd(ValueObject &backend) + : SyntheticChildrenFrontEnd(backend) {} + + ~SyntheticValueProviderFrontEnd() override = default; + + size_t CalculateNumChildren() override { return 0; } + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } + + size_t GetIndexOfChildWithName(const ConstString &name) override { + return UINT32_MAX; + } + + bool Update() override { return false; } + + bool MightHaveChildren() override { return false; } + + lldb::ValueObjectSP GetSyntheticValue() override = 0; + +private: + DISALLOW_COPY_AND_ASSIGN(SyntheticValueProviderFrontEnd); +}; + +class SyntheticChildren { +public: + class Flags { + public: + Flags() : m_flags(lldb::eTypeOptionCascade) {} + + Flags(const Flags &other) : m_flags(other.m_flags) {} + + Flags(uint32_t value) : m_flags(value) {} + + Flags &operator=(const Flags &rhs) { + if (&rhs != this) + m_flags = rhs.m_flags; + + return *this; + } + + Flags &operator=(const uint32_t &rhs) { + m_flags = rhs; + return *this; + } + + Flags &Clear() { + m_flags = 0; + return *this; + } + + bool GetCascades() const { + return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; + } + + Flags &SetCascades(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionCascade; + else + m_flags &= ~lldb::eTypeOptionCascade; + return *this; + } + + bool GetSkipPointers() const { + return (m_flags & lldb::eTypeOptionSkipPointers) == + lldb::eTypeOptionSkipPointers; + } + + Flags &SetSkipPointers(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipPointers; + else + m_flags &= ~lldb::eTypeOptionSkipPointers; + return *this; + } + + bool GetSkipReferences() const { + return (m_flags & lldb::eTypeOptionSkipReferences) == + lldb::eTypeOptionSkipReferences; + } + + Flags &SetSkipReferences(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipReferences; + else + m_flags &= ~lldb::eTypeOptionSkipReferences; + return *this; + } + + bool GetNonCacheable() const { + return (m_flags & lldb::eTypeOptionNonCacheable) == + lldb::eTypeOptionNonCacheable; + } + + Flags &SetNonCacheable(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionNonCacheable; + else + m_flags &= ~lldb::eTypeOptionNonCacheable; + return *this; + } + + uint32_t GetValue() { return m_flags; } + + void SetValue(uint32_t value) { m_flags = value; } + + private: + uint32_t m_flags; + }; + + SyntheticChildren(const Flags &flags) : m_flags(flags) {} + + virtual ~SyntheticChildren() = default; + + bool Cascades() const { return m_flags.GetCascades(); } + + bool SkipsPointers() const { return m_flags.GetSkipPointers(); } + + bool SkipsReferences() const { return m_flags.GetSkipReferences(); } + + bool NonCacheable() const { return m_flags.GetNonCacheable(); } + + void SetCascades(bool value) { m_flags.SetCascades(value); } + + void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } + + void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } + + void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } + + uint32_t GetOptions() { return m_flags.GetValue(); } + + void SetOptions(uint32_t value) { m_flags.SetValue(value); } + + virtual bool IsScripted() = 0; + + virtual std::string GetDescription() = 0; + + virtual SyntheticChildrenFrontEnd::AutoPointer + GetFrontEnd(ValueObject &backend) = 0; + + typedef std::shared_ptr SharedPointer; + + uint32_t &GetRevision() { return m_my_revision; } + +protected: + uint32_t m_my_revision; + Flags m_flags; + +private: + DISALLOW_COPY_AND_ASSIGN(SyntheticChildren); +}; + +class TypeFilterImpl : public SyntheticChildren { + std::vector m_expression_paths; + +public: + TypeFilterImpl(const SyntheticChildren::Flags &flags) + : SyntheticChildren(flags), m_expression_paths() {} + + TypeFilterImpl(const SyntheticChildren::Flags &flags, + const std::initializer_list items) + : SyntheticChildren(flags), m_expression_paths() { + for (auto path : items) + AddExpressionPath(path); + } + + void AddExpressionPath(const char *path) { + AddExpressionPath(std::string(path)); + } + + void Clear() { m_expression_paths.clear(); } + + size_t GetCount() const { return m_expression_paths.size(); } + + const char *GetExpressionPathAtIndex(size_t i) const { + return m_expression_paths[i].c_str(); + } + + bool SetExpressionPathAtIndex(size_t i, const char *path) { + return SetExpressionPathAtIndex(i, std::string(path)); + } + + void AddExpressionPath(const std::string &path); + + bool SetExpressionPathAtIndex(size_t i, const std::string &path); + + bool IsScripted() override { return false; } + + std::string GetDescription() override; + + class FrontEnd : public SyntheticChildrenFrontEnd { + public: + FrontEnd(TypeFilterImpl *flt, ValueObject &backend) + : SyntheticChildrenFrontEnd(backend), filter(flt) {} + + ~FrontEnd() override = default; + + size_t CalculateNumChildren() override { return filter->GetCount(); } + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + if (idx >= filter->GetCount()) + return lldb::ValueObjectSP(); + return m_backend.GetSyntheticExpressionPathChild( + filter->GetExpressionPathAtIndex(idx), true); + } + + bool Update() override { return false; } + + bool MightHaveChildren() override { return filter->GetCount() > 0; } + + size_t GetIndexOfChildWithName(const ConstString &name) override; + + typedef std::shared_ptr SharedPointer; + + private: + TypeFilterImpl *filter; + + DISALLOW_COPY_AND_ASSIGN(FrontEnd); + }; + + SyntheticChildrenFrontEnd::AutoPointer + GetFrontEnd(ValueObject &backend) override { + return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend)); + } + + typedef std::shared_ptr SharedPointer; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl); +}; + +class CXXSyntheticChildren : public SyntheticChildren { +public: + typedef std::function + CreateFrontEndCallback; + CXXSyntheticChildren(const SyntheticChildren::Flags &flags, + const char *description, CreateFrontEndCallback callback) + : SyntheticChildren(flags), m_create_callback(callback), + m_description(description ? description : "") {} + + bool IsScripted() override { return false; } + + std::string GetDescription() override; + + SyntheticChildrenFrontEnd::AutoPointer + GetFrontEnd(ValueObject &backend) override { + return SyntheticChildrenFrontEnd::AutoPointer( + m_create_callback(this, backend.GetSP())); + } + +protected: + CreateFrontEndCallback m_create_callback; + std::string m_description; + +private: + DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren); +}; + +#ifndef LLDB_DISABLE_PYTHON + +class ScriptedSyntheticChildren : public SyntheticChildren { + std::string m_python_class; + std::string m_python_code; + +public: + ScriptedSyntheticChildren(const SyntheticChildren::Flags &flags, + const char *pclass, const char *pcode = nullptr) + : SyntheticChildren(flags), m_python_class(), m_python_code() { + if (pclass) + m_python_class = pclass; + if (pcode) + m_python_code = pcode; + } + + const char *GetPythonClassName() { return m_python_class.c_str(); } + + const char *GetPythonCode() { return m_python_code.c_str(); } + + void SetPythonClassName(const char *fname) { + m_python_class.assign(fname); + m_python_code.clear(); + } + + void SetPythonCode(const char *script) { m_python_code.assign(script); } + + std::string GetDescription() override; + + bool IsScripted() override { return true; } + + class FrontEnd : public SyntheticChildrenFrontEnd { + public: + FrontEnd(std::string pclass, ValueObject &backend); + + ~FrontEnd() override; + + bool IsValid(); + + size_t CalculateNumChildren() override; + + size_t CalculateNumChildren(uint32_t max) override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(const ConstString &name) override; + + lldb::ValueObjectSP GetSyntheticValue() override; + + ConstString GetSyntheticTypeName() override; + + typedef std::shared_ptr SharedPointer; + + private: + std::string m_python_class; + StructuredData::ObjectSP m_wrapper_sp; + ScriptInterpreter *m_interpreter; + + DISALLOW_COPY_AND_ASSIGN(FrontEnd); + }; + + SyntheticChildrenFrontEnd::AutoPointer + GetFrontEnd(ValueObject &backend) override { + auto synth_ptr = SyntheticChildrenFrontEnd::AutoPointer( + new FrontEnd(m_python_class, backend)); + if (synth_ptr && ((FrontEnd *)synth_ptr.get())->IsValid()) + return synth_ptr; + return nullptr; + } + +private: + DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren); +}; +#endif +} // namespace lldb_private + +#endif // lldb_TypeSynthetic_h_ diff --git a/include/lldb/DataFormatters/TypeValidator.h b/include/lldb/DataFormatters/TypeValidator.h new file mode 100644 index 000000000..3c414e393 --- /dev/null +++ b/include/lldb/DataFormatters/TypeValidator.h @@ -0,0 +1,207 @@ +//===-- TypeValidator.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_TypeValidator_h_ +#define lldb_TypeValidator_h_ + +// C Includes + +// C++ Includes +#include +#include + +// Other libraries and framework includes + +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private-enumerations.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { + +class TypeValidatorImpl { +public: + class Flags { + public: + Flags() : m_flags(lldb::eTypeOptionCascade) {} + + Flags(const Flags &other) : m_flags(other.m_flags) {} + + Flags(uint32_t value) : m_flags(value) {} + + Flags &operator=(const Flags &rhs) { + if (&rhs != this) + m_flags = rhs.m_flags; + + return *this; + } + + Flags &operator=(const uint32_t &rhs) { + m_flags = rhs; + return *this; + } + + Flags &Clear() { + m_flags = 0; + return *this; + } + + bool GetCascades() const { + return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade; + } + + Flags &SetCascades(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionCascade; + else + m_flags &= ~lldb::eTypeOptionCascade; + return *this; + } + + bool GetSkipPointers() const { + return (m_flags & lldb::eTypeOptionSkipPointers) == + lldb::eTypeOptionSkipPointers; + } + + Flags &SetSkipPointers(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipPointers; + else + m_flags &= ~lldb::eTypeOptionSkipPointers; + return *this; + } + + bool GetSkipReferences() const { + return (m_flags & lldb::eTypeOptionSkipReferences) == + lldb::eTypeOptionSkipReferences; + } + + Flags &SetSkipReferences(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionSkipReferences; + else + m_flags &= ~lldb::eTypeOptionSkipReferences; + return *this; + } + + bool GetNonCacheable() const { + return (m_flags & lldb::eTypeOptionNonCacheable) == + lldb::eTypeOptionNonCacheable; + } + + Flags &SetNonCacheable(bool value = true) { + if (value) + m_flags |= lldb::eTypeOptionNonCacheable; + else + m_flags &= ~lldb::eTypeOptionNonCacheable; + return *this; + } + + uint32_t GetValue() { return m_flags; } + + void SetValue(uint32_t value) { m_flags = value; } + + private: + uint32_t m_flags; + }; + + TypeValidatorImpl(const Flags &flags = Flags()); + + typedef std::shared_ptr SharedPointer; + + virtual ~TypeValidatorImpl(); + + bool Cascades() const { return m_flags.GetCascades(); } + bool SkipsPointers() const { return m_flags.GetSkipPointers(); } + bool SkipsReferences() const { return m_flags.GetSkipReferences(); } + bool NonCacheable() const { return m_flags.GetNonCacheable(); } + + void SetCascades(bool value) { m_flags.SetCascades(value); } + + void SetSkipsPointers(bool value) { m_flags.SetSkipPointers(value); } + + void SetSkipsReferences(bool value) { m_flags.SetSkipReferences(value); } + + void SetNonCacheable(bool value) { m_flags.SetNonCacheable(value); } + + uint32_t GetOptions() { return m_flags.GetValue(); } + + void SetOptions(uint32_t value) { m_flags.SetValue(value); } + + uint32_t &GetRevision() { return m_my_revision; } + + enum class Type { eTypeUnknown, eTypeCXX }; + + struct ValidationResult { + TypeValidatorResult m_result; + std::string m_message; + }; + + virtual Type GetType() { return Type::eTypeUnknown; } + + // we are using a ValueObject* instead of a ValueObjectSP because we do not + // need to hold on to this for + // extended periods of time and we trust the ValueObject to stay around for as + // long as it is required + // for us to generate its value + virtual ValidationResult FormatObject(ValueObject *valobj) const = 0; + + virtual std::string GetDescription() = 0; + + static ValidationResult Success(); + + static ValidationResult Failure(std::string message); + +protected: + Flags m_flags; + uint32_t m_my_revision; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeValidatorImpl); +}; + +class TypeValidatorImpl_CXX : public TypeValidatorImpl { +public: + typedef std::function + ValidatorFunction; + + TypeValidatorImpl_CXX(ValidatorFunction f, std::string d, + const TypeValidatorImpl::Flags &flags = Flags()); + + typedef std::shared_ptr SharedPointer; + + ~TypeValidatorImpl_CXX() override; + + ValidatorFunction GetValidatorFunction() const { + return m_validator_function; + } + + void SetValidatorFunction(ValidatorFunction f) { m_validator_function = f; } + + TypeValidatorImpl::Type GetType() override { + return TypeValidatorImpl::Type::eTypeCXX; + } + + ValidationResult FormatObject(ValueObject *valobj) const override; + + std::string GetDescription() override; + +protected: + std::string m_description; + ValidatorFunction m_validator_function; + +private: + DISALLOW_COPY_AND_ASSIGN(TypeValidatorImpl_CXX); +}; + +} // namespace lldb_private + +#endif // lldb_TypeValidator_h_ diff --git a/include/lldb/DataFormatters/ValueObjectPrinter.h b/include/lldb/DataFormatters/ValueObjectPrinter.h new file mode 100644 index 000000000..418514368 --- /dev/null +++ b/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -0,0 +1,166 @@ +//===-- ValueObjectPrinter.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_ValueObjectPrinter_h_ +#define lldb_ValueObjectPrinter_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/lldb-public.h" + +#include "lldb/Utility/Flags.h" + +#include "lldb/DataFormatters/DumpValueObjectOptions.h" +#include "lldb/Symbol/CompilerType.h" + +//#include +//#include +//#include + +namespace lldb_private { + +class ValueObjectPrinter { +public: + ValueObjectPrinter(ValueObject *valobj, Stream *s); + + ValueObjectPrinter(ValueObject *valobj, Stream *s, + const DumpValueObjectOptions &options); + + ~ValueObjectPrinter() {} + + bool PrintValueObject(); + +protected: + typedef std::set InstancePointersSet; + typedef std::shared_ptr InstancePointersSetSP; + + InstancePointersSetSP m_printed_instance_pointers; + + // only this class (and subclasses, if any) should ever be concerned with + // the depth mechanism + ValueObjectPrinter(ValueObject *valobj, Stream *s, + const DumpValueObjectOptions &options, + const DumpValueObjectOptions::PointerDepth &ptr_depth, + uint32_t curr_depth, + InstancePointersSetSP printed_instance_pointers); + + // we should actually be using delegating constructors here + // but some versions of GCC still have trouble with those + void Init(ValueObject *valobj, Stream *s, + const DumpValueObjectOptions &options, + const DumpValueObjectOptions::PointerDepth &ptr_depth, + uint32_t curr_depth, + InstancePointersSetSP printed_instance_pointers); + + bool GetMostSpecializedValue(); + + const char *GetDescriptionForDisplay(); + + const char *GetRootNameForDisplay(const char *if_fail = nullptr); + + bool ShouldPrintValueObject(); + + bool ShouldPrintValidation(); + + bool IsNil(); + + bool IsUninitialized(); + + bool IsPtr(); + + bool IsRef(); + + bool IsInstancePointer(); + + bool IsAggregate(); + + bool PrintValidationMarkerIfNeeded(); + + bool PrintValidationErrorIfNeeded(); + + bool PrintLocationIfNeeded(); + + void PrintDecl(); + + bool CheckScopeIfNeeded(); + + bool ShouldPrintEmptyBrackets(bool value_printed, bool summary_printed); + + TypeSummaryImpl *GetSummaryFormatter(bool null_if_omitted = true); + + void GetValueSummaryError(std::string &value, std::string &summary, + std::string &error); + + bool PrintValueAndSummaryIfNeeded(bool &value_printed, bool &summary_printed); + + bool PrintObjectDescriptionIfNeeded(bool value_printed, bool summary_printed); + + bool + ShouldPrintChildren(bool is_failed_description, + DumpValueObjectOptions::PointerDepth &curr_ptr_depth); + + bool ShouldExpandEmptyAggregates(); + + ValueObject *GetValueObjectForChildrenGeneration(); + + void PrintChildrenPreamble(); + + void PrintChildrenPostamble(bool print_dotdotdot); + + lldb::ValueObjectSP GenerateChild(ValueObject *synth_valobj, size_t idx); + + void PrintChild(lldb::ValueObjectSP child_sp, + const DumpValueObjectOptions::PointerDepth &curr_ptr_depth); + + uint32_t GetMaxNumChildrenToPrint(bool &print_dotdotdot); + + void + PrintChildren(bool value_printed, bool summary_printed, + const DumpValueObjectOptions::PointerDepth &curr_ptr_depth); + + void PrintChildrenIfNeeded(bool value_printed, bool summary_printed); + + bool PrintChildrenOneLiner(bool hide_names); + +private: + ValueObject *m_orig_valobj; + ValueObject *m_valobj; + Stream *m_stream; + DumpValueObjectOptions m_options; + Flags m_type_flags; + CompilerType m_compiler_type; + DumpValueObjectOptions::PointerDepth m_ptr_depth; + uint32_t m_curr_depth; + LazyBool m_should_print; + LazyBool m_is_nil; + LazyBool m_is_uninit; + LazyBool m_is_ptr; + LazyBool m_is_ref; + LazyBool m_is_aggregate; + LazyBool m_is_instance_ptr; + std::pair m_summary_formatter; + std::string m_value; + std::string m_summary; + std::string m_error; + bool m_val_summary_ok; + std::pair m_validation; + + friend struct StringSummaryFormat; + + DISALLOW_COPY_AND_ASSIGN(ValueObjectPrinter); +}; + +} // namespace lldb_private + +#endif // lldb_ValueObjectPrinter_h_ diff --git a/include/lldb/DataFormatters/VectorIterator.h b/include/lldb/DataFormatters/VectorIterator.h new file mode 100644 index 000000000..fcf5aba6e --- /dev/null +++ b/include/lldb/DataFormatters/VectorIterator.h @@ -0,0 +1,45 @@ +//===-- VectorIterator.h ----------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_VectorIterator_h_ +#define liblldb_VectorIterator_h_ + +#include "lldb/lldb-forward.h" + +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/ConstString.h" + +namespace lldb_private { +namespace formatters { +class VectorIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, + ConstString item_name); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(const ConstString &name) override; + +private: + ExecutionContextRef m_exe_ctx_ref; + ConstString m_item_name; + lldb::ValueObjectSP m_item_sp; +}; + +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_CF_h_ diff --git a/include/lldb/DataFormatters/VectorType.h b/include/lldb/DataFormatters/VectorType.h new file mode 100644 index 000000000..4ca0c4519 --- /dev/null +++ b/include/lldb/DataFormatters/VectorType.h @@ -0,0 +1,25 @@ +//===-- VectorType.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_VectorType_h_ +#define liblldb_VectorType_h_ + +#include "lldb/lldb-forward.h" + +namespace lldb_private { +namespace formatters { +bool VectorTypeSummaryProvider(ValueObject &, Stream &, + const TypeSummaryOptions &); + +SyntheticChildrenFrontEnd * +VectorTypeSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_VectorType_h_ diff --git a/include/lldb/Expression/DWARFExpression.h b/include/lldb/Expression/DWARFExpression.h new file mode 100644 index 000000000..1816c3b7a --- /dev/null +++ b/include/lldb/Expression/DWARFExpression.h @@ -0,0 +1,444 @@ +//===-- 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/Core/Address.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-private.h" +#include + +class DWARFCompileUnit; + +namespace lldb_private { + +class ClangExpressionDeclMap; +class ClangExpressionVariable; +class ClangExpressionVariableList; + +//---------------------------------------------------------------------- +/// @class DWARFExpression DWARFExpression.h "lldb/Expression/DWARFExpression.h" +/// @brief Encapsulates a DWARF location expression and interprets it. +/// +/// DWARF location expressions are used in two ways by LLDB. The first +/// use is to find entities specified in the debug information, since +/// their locations are specified in precisely this language. The second +/// is to interpret expressions without having to run the target in cases +/// where the overhead from copying JIT-compiled code into the target is +/// too high or where the target cannot be run. This class encapsulates +/// a single DWARF location expression or a location list and interprets +/// it. +//---------------------------------------------------------------------- +class DWARFExpression { +public: + enum LocationListFormat : uint8_t { + NonLocationList, // Not a location list + RegularLocationList, // Location list format used in non-split dwarf files + SplitDwarfLocationList, // Location list format used in split dwarf files + }; + + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + explicit DWARFExpression(DWARFCompileUnit *dwarf_cu); + + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] data + /// A data extractor configured to read the DWARF location expression's + /// bytecode. + /// + /// @param[in] data_offset + /// The offset of the location expression in the extractor. + /// + /// @param[in] data_length + /// The byte length of the location expression. + //------------------------------------------------------------------ + DWARFExpression(lldb::ModuleSP module, const DataExtractor &data, + DWARFCompileUnit *dwarf_cu, lldb::offset_t data_offset, + lldb::offset_t data_length); + + //------------------------------------------------------------------ + /// Copy constructor + //------------------------------------------------------------------ + DWARFExpression(const DWARFExpression &rhs); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~DWARFExpression(); + + //------------------------------------------------------------------ + /// Print the description of the expression to a stream + /// + /// @param[in] s + /// The stream to print to. + /// + /// @param[in] level + /// The level of verbosity to use. + /// + /// @param[in] location_list_base_addr + /// If this is a location list based expression, this is the + /// address of the object that owns it. NOTE: this value is + /// different from the DWARF version of the location list base + /// address which is compile unit relative. This base address + /// is the address of the object that owns the location list. + /// + /// @param[in] abi + /// An optional ABI plug-in that can be used to resolve register + /// names. + //------------------------------------------------------------------ + void GetDescription(Stream *s, lldb::DescriptionLevel level, + lldb::addr_t location_list_base_addr, ABI *abi) const; + + //------------------------------------------------------------------ + /// Return true if the location expression contains data + //------------------------------------------------------------------ + bool IsValid() const; + + //------------------------------------------------------------------ + /// Return true if a location list was provided + //------------------------------------------------------------------ + bool IsLocationList() const; + + //------------------------------------------------------------------ + /// Search for a load address in the location list + /// + /// @param[in] process + /// The process to use when resolving the load address + /// + /// @param[in] addr + /// The address to resolve + /// + /// @return + /// True if IsLocationList() is true and the address was found; + /// false otherwise. + //------------------------------------------------------------------ + // bool + // LocationListContainsLoadAddress (Process* process, const Address &addr) + // const; + // + bool LocationListContainsAddress(lldb::addr_t loclist_base_addr, + lldb::addr_t addr) const; + + //------------------------------------------------------------------ + /// If a location is not a location list, return true if the location + /// contains a DW_OP_addr () opcode in the stream that matches \a + /// file_addr. If file_addr is LLDB_INVALID_ADDRESS, the this + /// function will return true if the variable there is any DW_OP_addr + /// in a location that (yet still is NOT a location list). This helps + /// us detect if a variable is a global or static variable since + /// there is no other indication from DWARF debug info. + /// + /// @param[in] op_addr_idx + /// The DW_OP_addr index to retrieve in case there is more than + /// one DW_OP_addr opcode in the location byte stream. + /// + /// @param[out] error + /// If the location stream contains unknown DW_OP opcodes or the + /// data is missing, \a error will be set to \b true. + /// + /// @return + /// LLDB_INVALID_ADDRESS if the location doesn't contain a + /// DW_OP_addr for \a op_addr_idx, otherwise a valid file address + //------------------------------------------------------------------ + lldb::addr_t GetLocation_DW_OP_addr(uint32_t op_addr_idx, bool &error) const; + + bool Update_DW_OP_addr(lldb::addr_t file_addr); + + bool ContainsThreadLocalStorage() const; + + bool LinkThreadLocalStorage( + lldb::ModuleSP new_module_sp, + std::function const + &link_address_callback); + + //------------------------------------------------------------------ + /// Make the expression parser read its location information from a + /// given data source. Does not change the offset and length + /// + /// @param[in] data + /// A data extractor configured to read the DWARF location expression's + /// bytecode. + //------------------------------------------------------------------ + void SetOpcodeData(const DataExtractor &data); + + //------------------------------------------------------------------ + /// Make the expression parser read its location information from a + /// given data source + /// + /// @param[in] module_sp + /// The module that defines the DWARF expression. + /// + /// @param[in] data + /// A data extractor configured to read the DWARF location expression's + /// bytecode. + /// + /// @param[in] data_offset + /// The offset of the location expression in the extractor. + /// + /// @param[in] data_length + /// The byte length of the location expression. + //------------------------------------------------------------------ + void SetOpcodeData(lldb::ModuleSP module_sp, const DataExtractor &data, + lldb::offset_t data_offset, lldb::offset_t data_length); + + //------------------------------------------------------------------ + /// Copy the DWARF location expression into a local buffer. + /// + /// It is a good idea to copy the data so we don't keep the entire + /// object file worth of data around just for a few bytes of location + /// expression. LLDB typically will mmap the entire contents of debug + /// information files, and if we use SetOpcodeData, it will get a + /// shared reference to all of this data for the and cause the object + /// file to have to stay around. Even worse, a very very large ".a" + /// that contains one or more .o files could end up being referenced. + /// Location lists are typically small so even though we are copying + /// the data, it shouldn't amount to that much for the variables we + /// end up parsing. + /// + /// @param[in] module_sp + /// The module that defines the DWARF expression. + /// + /// @param[in] data + /// A data extractor configured to read and copy the DWARF + /// location expression's bytecode. + /// + /// @param[in] data_offset + /// The offset of the location expression in the extractor. + /// + /// @param[in] data_length + /// The byte length of the location expression. + //------------------------------------------------------------------ + void CopyOpcodeData(lldb::ModuleSP module_sp, const DataExtractor &data, + lldb::offset_t data_offset, lldb::offset_t data_length); + + void CopyOpcodeData(const void *data, lldb::offset_t data_length, + lldb::ByteOrder byte_order, uint8_t addr_byte_size); + + void CopyOpcodeData(uint64_t const_value, + lldb::offset_t const_value_byte_size, + uint8_t addr_byte_size); + + //------------------------------------------------------------------ + /// Tells the expression that it refers to a location list. + /// + /// @param[in] slide + /// This value should be a slide that is applied to any values + /// in the location list data so the values become zero based + /// offsets into the object that owns the location list. We need + /// to make location lists relative to the objects that own them + /// so we can relink addresses on the fly. + //------------------------------------------------------------------ + void SetLocationListSlide(lldb::addr_t slide); + + //------------------------------------------------------------------ + /// Return the call-frame-info style register kind + //------------------------------------------------------------------ + int GetRegisterKind(); + + //------------------------------------------------------------------ + /// Set the call-frame-info style register kind + /// + /// @param[in] reg_kind + /// The register kind. + //------------------------------------------------------------------ + void SetRegisterKind(lldb::RegisterKind reg_kind); + + //------------------------------------------------------------------ + /// Wrapper for the static evaluate function that accepts an + /// ExecutionContextScope instead of an ExecutionContext and uses + /// member variables to populate many operands + //------------------------------------------------------------------ + bool Evaluate(ExecutionContextScope *exe_scope, + ClangExpressionVariableList *expr_locals, + ClangExpressionDeclMap *decl_map, + lldb::addr_t loclist_base_load_addr, + const Value *initial_value_ptr, const Value *object_address_ptr, + Value &result, Status *error_ptr) const; + + //------------------------------------------------------------------ + /// Wrapper for the static evaluate function that uses member + /// variables to populate many operands + //------------------------------------------------------------------ + bool Evaluate(ExecutionContext *exe_ctx, + ClangExpressionVariableList *expr_locals, + ClangExpressionDeclMap *decl_map, RegisterContext *reg_ctx, + lldb::addr_t loclist_base_load_addr, + const Value *initial_value_ptr, const Value *object_address_ptr, + Value &result, Status *error_ptr) const; + + //------------------------------------------------------------------ + /// Evaluate a DWARF location expression in a particular context + /// + /// @param[in] exe_ctx + /// The execution context in which to evaluate the location + /// expression. The location expression may access the target's + /// memory, especially if it comes from the expression parser. + /// + /// @param[in] opcode_ctx + /// The module which defined the expression. + /// + /// @param[in] opcodes + /// This is a static method so the opcodes need to be provided + /// explicitly. + /// + /// @param[in] expr_locals + /// If the location expression was produced by the expression parser, + /// the list of local variables referenced by the DWARF expression. + /// This list should already have been populated during parsing; + /// the DWARF expression refers to variables by index. Can be NULL if + /// the location expression uses no locals. + /// + /// @param[in] decl_map + /// If the location expression was produced by the expression parser, + /// the list of external variables referenced by the location + /// expression. Can be NULL if the location expression uses no + /// external variables. + /// + /// @param[in] reg_ctx + /// An optional parameter which provides a RegisterContext for use + /// when evaluating the expression (i.e. for fetching register values). + /// Normally this will come from the ExecutionContext's StackFrame but + /// in the case where an expression needs to be evaluated while building + /// the stack frame list, this short-cut is available. + /// + /// @param[in] offset + /// The offset of the location expression in the data extractor. + /// + /// @param[in] length + /// The length in bytes of the location expression. + /// + /// @param[in] reg_set + /// The call-frame-info style register kind. + /// + /// @param[in] initial_value_ptr + /// A value to put on top of the interpreter stack before evaluating + /// the expression, if the expression is parametrized. Can be NULL. + /// + /// @param[in] result + /// A value into which the result of evaluating the expression is + /// to be placed. + /// + /// @param[in] error_ptr + /// If non-NULL, used to report errors in expression evaluation. + /// + /// @return + /// True on success; false otherwise. If error_ptr is non-NULL, + /// details of the failure are provided through it. + //------------------------------------------------------------------ + static bool + Evaluate(ExecutionContext *exe_ctx, ClangExpressionVariableList *expr_locals, + ClangExpressionDeclMap *decl_map, RegisterContext *reg_ctx, + lldb::ModuleSP opcode_ctx, const DataExtractor &opcodes, + DWARFCompileUnit *dwarf_cu, const lldb::offset_t offset, + const lldb::offset_t length, const lldb::RegisterKind reg_set, + const Value *initial_value_ptr, const Value *object_address_ptr, + Value &result, Status *error_ptr); + + //------------------------------------------------------------------ + /// Loads a ClangExpressionVariableList into the object + /// + /// @param[in] locals + /// If non-NULL, the list of locals used by this expression. + /// See Evaluate(). + //------------------------------------------------------------------ + void SetExpressionLocalVariableList(ClangExpressionVariableList *locals); + + //------------------------------------------------------------------ + /// Loads a ClangExpressionDeclMap into the object + /// + /// @param[in] locals + /// If non-NULL, the list of external variables used by this + /// expression. See Evaluate(). + //------------------------------------------------------------------ + void SetExpressionDeclMap(ClangExpressionDeclMap *decl_map); + + bool GetExpressionData(DataExtractor &data) const { + data = m_data; + return data.GetByteSize() > 0; + } + + bool DumpLocationForAddress(Stream *s, lldb::DescriptionLevel level, + lldb::addr_t loclist_base_load_addr, + lldb::addr_t address, ABI *abi); + + static size_t LocationListSize(const DWARFCompileUnit *dwarf_cu, + const DataExtractor &debug_loc_data, + lldb::offset_t offset); + + static bool PrintDWARFExpression(Stream &s, const DataExtractor &data, + int address_size, int dwarf_ref_size, + bool location_expression); + + static void PrintDWARFLocationList(Stream &s, const DWARFCompileUnit *cu, + const DataExtractor &debug_loc_data, + lldb::offset_t offset); + + bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op); + +protected: + //------------------------------------------------------------------ + /// Pretty-prints the location expression to a stream + /// + /// @param[in] stream + /// The stream to use for pretty-printing. + /// + /// @param[in] offset + /// The offset into the data buffer of the opcodes to be printed. + /// + /// @param[in] length + /// The length in bytes of the opcodes to be printed. + /// + /// @param[in] level + /// The level of detail to use in pretty-printing. + /// + /// @param[in] abi + /// An optional ABI plug-in that can be used to resolve register + /// names. + //------------------------------------------------------------------ + void DumpLocation(Stream *s, lldb::offset_t offset, lldb::offset_t length, + lldb::DescriptionLevel level, ABI *abi) const; + + bool GetLocation(lldb::addr_t base_addr, lldb::addr_t pc, + lldb::offset_t &offset, lldb::offset_t &len); + + static bool AddressRangeForLocationListEntry( + const DWARFCompileUnit *dwarf_cu, const DataExtractor &debug_loc_data, + lldb::offset_t *offset_ptr, lldb::addr_t &low_pc, lldb::addr_t &high_pc); + + bool GetOpAndEndOffsets(StackFrame &frame, lldb::offset_t &op_offset, + lldb::offset_t &end_offset); + + //------------------------------------------------------------------ + /// Classes that inherit from DWARFExpression can see and modify these + //------------------------------------------------------------------ + + lldb::ModuleWP m_module_wp; ///< Module which defined this expression. + DataExtractor m_data; ///< A data extractor capable of reading opcode bytes + DWARFCompileUnit *m_dwarf_cu; ///< The DWARF compile unit this expression + ///belongs to. It is used + ///< to evaluate values indexing into the .debug_addr section (e.g. + ///< DW_OP_GNU_addr_index, DW_OP_GNU_const_index) + lldb::RegisterKind + m_reg_kind; ///< One of the defines that starts with LLDB_REGKIND_ + lldb::addr_t m_loclist_slide; ///< A value used to slide the location list + ///offsets so that + ///< they are relative to the object that owns the location list + ///< (the function for frame base and variable location lists) +}; + +} // namespace lldb_private + +#endif // liblldb_DWARFExpression_h_ diff --git a/include/lldb/Expression/DiagnosticManager.h b/include/lldb/Expression/DiagnosticManager.h new file mode 100644 index 000000000..83e67df26 --- /dev/null +++ b/include/lldb/Expression/DiagnosticManager.h @@ -0,0 +1,166 @@ +//===-- DiagnosticManager.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_DiagnosticManager_h +#define lldb_DiagnosticManager_h + +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +#include "llvm/ADT/StringRef.h" + +#include +#include + +namespace lldb_private { + +enum DiagnosticOrigin { + eDiagnosticOriginUnknown = 0, + eDiagnosticOriginLLDB, + eDiagnosticOriginClang, + eDiagnosticOriginGo, + eDiagnosticOriginSwift, + eDiagnosticOriginLLVM +}; + +enum DiagnosticSeverity { + eDiagnosticSeverityError, + eDiagnosticSeverityWarning, + eDiagnosticSeverityRemark +}; + +const uint32_t LLDB_INVALID_COMPILER_ID = UINT32_MAX; + +class Diagnostic { + friend class DiagnosticManager; + +public: + DiagnosticOrigin getKind() const { return m_origin; } + + static bool classof(const Diagnostic *diag) { + DiagnosticOrigin kind = diag->getKind(); + switch (kind) { + case eDiagnosticOriginUnknown: + case eDiagnosticOriginLLDB: + case eDiagnosticOriginGo: + case eDiagnosticOriginLLVM: + return true; + case eDiagnosticOriginClang: + case eDiagnosticOriginSwift: + return false; + } + } + + Diagnostic(llvm::StringRef message, DiagnosticSeverity severity, + DiagnosticOrigin origin, uint32_t compiler_id) + : m_message(message), m_severity(severity), m_origin(origin), + m_compiler_id(compiler_id) {} + + Diagnostic(const Diagnostic &rhs) + : m_message(rhs.m_message), m_severity(rhs.m_severity), + m_origin(rhs.m_origin), m_compiler_id(rhs.m_compiler_id) {} + + virtual ~Diagnostic() = default; + + virtual bool HasFixIts() const { return false; } + + DiagnosticSeverity GetSeverity() const { return m_severity; } + + uint32_t GetCompilerID() const { return m_compiler_id; } + + llvm::StringRef GetMessage() const { return m_message; } + + void AppendMessage(llvm::StringRef message, + bool precede_with_newline = true) { + if (precede_with_newline) + m_message.push_back('\n'); + m_message.append(message); + } + +protected: + std::string m_message; + DiagnosticSeverity m_severity; + DiagnosticOrigin m_origin; + uint32_t m_compiler_id; // Compiler-specific diagnostic ID +}; + +typedef std::vector DiagnosticList; + +class DiagnosticManager { +public: + void Clear() { + m_diagnostics.clear(); + m_fixed_expression.clear(); + } + + // The diagnostic manager holds a list of diagnostics, which are owned by the + // manager. + const DiagnosticList &Diagnostics() { return m_diagnostics; } + + ~DiagnosticManager() { + for (Diagnostic *diag : m_diagnostics) { + delete diag; + } + } + + bool HasFixIts() { + for (Diagnostic *diag : m_diagnostics) { + if (diag->HasFixIts()) + return true; + } + return false; + } + + void AddDiagnostic(llvm::StringRef message, DiagnosticSeverity severity, + DiagnosticOrigin origin, + uint32_t compiler_id = LLDB_INVALID_COMPILER_ID) { + m_diagnostics.push_back( + new Diagnostic(message, severity, origin, compiler_id)); + } + + void AddDiagnostic(Diagnostic *diagnostic) { + m_diagnostics.push_back(diagnostic); + } + + void CopyDiagnostics(DiagnosticManager &otherDiagnostics); + + size_t Printf(DiagnosticSeverity severity, const char *format, ...) + __attribute__((format(printf, 3, 4))); + size_t PutString(DiagnosticSeverity severity, llvm::StringRef str); + + void AppendMessageToDiagnostic(llvm::StringRef str) { + if (!m_diagnostics.empty()) { + m_diagnostics.back()->AppendMessage(str); + } + } + + // Returns a string containing errors in this format: + // + // "error: error text\n + // warning: warning text\n + // remark text\n" + std::string GetString(char separator = '\n'); + + void Dump(Log *log); + + const std::string &GetFixedExpression() { return m_fixed_expression; } + + // Moves fixed_expression to the internal storage. + void SetFixedExpression(std::string fixed_expression) { + m_fixed_expression = std::move(fixed_expression); + fixed_expression.clear(); + } + +protected: + DiagnosticList m_diagnostics; + std::string m_fixed_expression; +}; +} + +#endif /* lldb_DiagnosticManager_h */ diff --git a/include/lldb/Expression/Expression.h b/include/lldb/Expression/Expression.h new file mode 100644 index 000000000..860444e9c --- /dev/null +++ b/include/lldb/Expression/Expression.h @@ -0,0 +1,129 @@ +//===-- Expression.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Expression_h_ +#define liblldb_Expression_h_ + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes + +#include "lldb/Expression/ExpressionTypeSystemHelper.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class RecordingMemoryManager; + +//---------------------------------------------------------------------- +/// @class Expression Expression.h "lldb/Expression/Expression.h" +/// @brief Encapsulates a single expression for use in lldb +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. Expression encapsulates +/// the objects needed to parse and interpret or JIT an expression. It +/// uses the expression parser appropriate to the language of the expression +/// to produce LLVM IR from the expression. +//---------------------------------------------------------------------- +class Expression { +public: + enum ResultType { eResultTypeAny, eResultTypeId }; + + Expression(Target &target); + + Expression(ExecutionContextScope &exe_scope); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~Expression() {} + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + virtual const char *Text() = 0; + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + virtual const char *FunctionName() = 0; + + //------------------------------------------------------------------ + /// Return the language that should be used when parsing. To use + /// the default, return eLanguageTypeUnknown. + //------------------------------------------------------------------ + virtual lldb::LanguageType Language() { return lldb::eLanguageTypeUnknown; } + + //------------------------------------------------------------------ + /// Return the desired result type of the function, or + /// eResultTypeAny if indifferent. + //------------------------------------------------------------------ + virtual ResultType DesiredResultType() { return eResultTypeAny; } + + //------------------------------------------------------------------ + /// Flags + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Return true if validation code should be inserted into the + /// expression. + //------------------------------------------------------------------ + virtual bool NeedsValidation() = 0; + + //------------------------------------------------------------------ + /// Return true if external variables in the expression should be + /// resolved. + //------------------------------------------------------------------ + virtual bool NeedsVariableResolution() = 0; + + virtual EvaluateExpressionOptions *GetOptions() { return nullptr; }; + + //------------------------------------------------------------------ + /// Return the address of the function's JIT-compiled code, or + /// LLDB_INVALID_ADDRESS if the function is not JIT compiled + //------------------------------------------------------------------ + lldb::addr_t StartAddress() { return m_jit_start_addr; } + + //------------------------------------------------------------------ + /// Called to notify the expression that it is about to be executed. + //------------------------------------------------------------------ + virtual void WillStartExecuting() {} + + //------------------------------------------------------------------ + /// Called to notify the expression that its execution has finished. + //------------------------------------------------------------------ + virtual void DidFinishExecuting() {} + + virtual ExpressionTypeSystemHelper *GetTypeSystemHelper() { return nullptr; } + +protected: + lldb::TargetWP m_target_wp; /// Expression's always have to have a target... + lldb::ProcessWP m_jit_process_wp; /// An expression might have a process, but + /// it doesn't need to (e.g. calculator + /// mode.) + lldb::addr_t m_jit_start_addr; ///< The address of the JITted function within + ///the JIT allocation. LLDB_INVALID_ADDRESS if + ///invalid. + lldb::addr_t m_jit_end_addr; ///< The address of the JITted function within + ///the JIT allocation. LLDB_INVALID_ADDRESS if + ///invalid. +}; + +} // namespace lldb_private + +#endif // liblldb_Expression_h_ diff --git a/include/lldb/Expression/ExpressionParser.h b/include/lldb/Expression/ExpressionParser.h new file mode 100644 index 000000000..19526d28b --- /dev/null +++ b/include/lldb/Expression/ExpressionParser.h @@ -0,0 +1,125 @@ +//===-- ExpressionParser.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ExpressionParser_h_ +#define liblldb_ExpressionParser_h_ + +#include "lldb/Utility/Status.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { + +class IRExecutionUnit; + +//---------------------------------------------------------------------- +/// @class ExpressionParser ExpressionParser.h +/// "lldb/Expression/ExpressionParser.h" +/// @brief Encapsulates an instance of a compiler that can parse expressions. +/// +/// ExpressionParser is the base class for llvm based Expression parsers. +//---------------------------------------------------------------------- +class ExpressionParser { +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// Initializes class variables. + /// + /// @param[in] exe_scope, + /// If non-NULL, an execution context scope that can help to + /// correctly create an expression with a valid process for + /// optional tuning Objective-C runtime support. Can be NULL. + /// + /// @param[in] expr + /// The expression to be parsed. + //------------------------------------------------------------------ + ExpressionParser(ExecutionContextScope *exe_scope, Expression &expr, + bool generate_debug_info) + : m_expr(expr), m_generate_debug_info(generate_debug_info) {} + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + virtual ~ExpressionParser(){}; + + //------------------------------------------------------------------ + /// Parse a single expression and convert it to IR using Clang. Don't + /// wrap the expression in anything at all. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager in which to store the errors and warnings. + /// + /// @return + /// The number of errors encountered during parsing. 0 means + /// success. + //------------------------------------------------------------------ + virtual unsigned Parse(DiagnosticManager &diagnostic_manager) = 0; + + //------------------------------------------------------------------ + /// Try to use the FixIts in the diagnostic_manager to rewrite the + /// expression. If successful, the rewritten expression is stored + /// in the diagnostic_manager, get it out with GetFixedExpression. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager containing fixit's to apply. + /// + /// @return + /// \b true if the rewrite was successful, \b false otherwise. + //------------------------------------------------------------------ + virtual bool RewriteExpression(DiagnosticManager &diagnostic_manager) { + return false; + } + + //------------------------------------------------------------------ + /// Ready an already-parsed expression for execution, possibly + /// evaluating it statically. + /// + /// @param[out] func_addr + /// The address to which the function has been written. + /// + /// @param[out] func_end + /// The end of the function's allocated memory region. (func_addr + /// and func_end do not delimit an allocated region; the allocated + /// region may begin before func_addr.) + /// + /// @param[in] execution_unit_sp + /// After parsing, ownership of the execution unit for + /// for the expression is handed to this shared pointer. + /// + /// @param[in] exe_ctx + /// The execution context to write the function into. + /// + /// @param[out] can_interpret + /// Set to true if the expression could be interpreted statically; + /// untouched otherwise. + /// + /// @param[in] execution_policy + /// Determines whether the expression must be JIT-compiled, must be + /// evaluated statically, or whether this decision may be made + /// opportunistically. + /// + /// @return + /// An error code indicating the success or failure of the operation. + /// Test with Success(). + //------------------------------------------------------------------ + virtual Status + PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end, + std::shared_ptr &execution_unit_sp, + ExecutionContext &exe_ctx, bool &can_interpret, + lldb_private::ExecutionPolicy execution_policy) = 0; + + bool GetGenerateDebugInfo() const { return m_generate_debug_info; } + +protected: + Expression &m_expr; ///< The expression to be parsed + bool m_generate_debug_info; +}; +} + +#endif // liblldb_ExpressionParser_h_ diff --git a/include/lldb/Expression/ExpressionSourceCode.h b/include/lldb/Expression/ExpressionSourceCode.h new file mode 100644 index 000000000..02fc72aaf --- /dev/null +++ b/include/lldb/Expression/ExpressionSourceCode.h @@ -0,0 +1,63 @@ +//===-- ExpressionSourceCode.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ExpressionSourceCode_h +#define liblldb_ExpressionSourceCode_h + +#include "lldb/lldb-enumerations.h" + +#include + +namespace lldb_private { + +class ExecutionContext; + +class ExpressionSourceCode { +public: + static const char *g_expression_prefix; + + static ExpressionSourceCode *CreateWrapped(const char *prefix, + const char *body) { + return new ExpressionSourceCode("$__lldb_expr", prefix, body, true); + } + + static ExpressionSourceCode *CreateUnwrapped(const char *name, + const char *body) { + return new ExpressionSourceCode(name, "", body, false); + } + + bool NeedsWrapping() const { return m_wrap; } + + const char *GetName() const { return m_name.c_str(); } + + bool GetText(std::string &text, lldb::LanguageType wrapping_language, + bool static_method, ExecutionContext &exe_ctx) const; + + // Given a string returned by GetText, find the beginning and end of the body + // passed to CreateWrapped. + // Return true if the bounds could be found. This will also work on text with + // FixItHints applied. + static bool GetOriginalBodyBounds(std::string transformed_text, + lldb::LanguageType wrapping_language, + size_t &start_loc, size_t &end_loc); + +private: + ExpressionSourceCode(const char *name, const char *prefix, const char *body, + bool wrap) + : m_name(name), m_prefix(prefix), m_body(body), m_wrap(wrap) {} + + std::string m_name; + std::string m_prefix; + std::string m_body; + bool m_wrap; +}; + +} // namespace lldb_private + +#endif diff --git a/include/lldb/Expression/ExpressionTypeSystemHelper.h b/include/lldb/Expression/ExpressionTypeSystemHelper.h new file mode 100644 index 000000000..20a5e67cf --- /dev/null +++ b/include/lldb/Expression/ExpressionTypeSystemHelper.h @@ -0,0 +1,50 @@ +//===-- ExpressionTypeSystemHelper.h ---------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ExpressionTypeSystemHelper_h +#define ExpressionTypeSystemHelper_h + +#include "llvm/Support/Casting.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class ExpressionTypeSystemHelper ExpressionTypeSystemHelper.h +/// "lldb/Expression/ExpressionTypeSystemHelper.h" +/// @brief A helper object that the Expression can pass to its ExpressionParser +/// to provide generic information that +/// any type of expression will need to supply. It's only job is to support +/// dyn_cast so that the expression parser +/// can cast it back to the requisite specific type. +/// +//---------------------------------------------------------------------- + +class ExpressionTypeSystemHelper { +public: + enum LLVMCastKind { + eKindClangHelper, + eKindSwiftHelper, + eKindGoHelper, + kNumKinds + }; + + LLVMCastKind getKind() const { return m_kind; } + + ExpressionTypeSystemHelper(LLVMCastKind kind) : m_kind(kind) {} + + ~ExpressionTypeSystemHelper() {} + +protected: + LLVMCastKind m_kind; +}; + +} // namespace lldb_private + +#endif /* ExpressionTypeSystemHelper_h */ diff --git a/include/lldb/Expression/ExpressionVariable.h b/include/lldb/Expression/ExpressionVariable.h new file mode 100644 index 000000000..c7570932c --- /dev/null +++ b/include/lldb/Expression/ExpressionVariable.h @@ -0,0 +1,268 @@ +//===-- ExpressionVariable.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ExpressionVariable_h_ +#define liblldb_ExpressionVariable_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "llvm/ADT/DenseMap.h" + +// Project includes +#include "lldb/Core/ValueObject.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { + +class ClangExpressionVariable; + +class ExpressionVariable + : public std::enable_shared_from_this { +public: + //---------------------------------------------------------------------- + // See TypeSystem.h for how to add subclasses to this. + //---------------------------------------------------------------------- + enum LLVMCastKind { eKindClang, eKindSwift, eKindGo, kNumKinds }; + + LLVMCastKind getKind() const { return m_kind; } + + ExpressionVariable(LLVMCastKind kind) : m_flags(0), m_kind(kind) {} + + virtual ~ExpressionVariable(); + + size_t GetByteSize() { return m_frozen_sp->GetByteSize(); } + + const ConstString &GetName() { return m_frozen_sp->GetName(); } + + lldb::ValueObjectSP GetValueObject() { return m_frozen_sp; } + + uint8_t *GetValueBytes(); + + void ValueUpdated() { m_frozen_sp->ValueUpdated(); } + + RegisterInfo *GetRegisterInfo() { + return m_frozen_sp->GetValue().GetRegisterInfo(); + } + + void SetRegisterInfo(const RegisterInfo *reg_info) { + return m_frozen_sp->GetValue().SetContext( + Value::eContextTypeRegisterInfo, const_cast(reg_info)); + } + + CompilerType GetCompilerType() { return m_frozen_sp->GetCompilerType(); } + + void SetCompilerType(const CompilerType &compiler_type) { + m_frozen_sp->GetValue().SetCompilerType(compiler_type); + } + + void SetName(const ConstString &name) { m_frozen_sp->SetName(name); } + + // this function is used to copy the address-of m_live_sp into m_frozen_sp + // this is necessary because the results of certain cast and + // pointer-arithmetic + // operations (such as those described in bugzilla issues 11588 and 11618) + // generate + // frozen objects that do not have a valid address-of, which can be + // troublesome when + // using synthetic children providers. Transferring the address-of the live + // object + // solves these issues and provides the expected user-level behavior + void TransferAddress(bool force = false) { + if (m_live_sp.get() == nullptr) + return; + + if (m_frozen_sp.get() == nullptr) + return; + + if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS)) + m_frozen_sp->SetLiveAddress(m_live_sp->GetLiveAddress()); + } + + enum Flags { + EVNone = 0, + EVIsLLDBAllocated = 1 << 0, ///< This variable is resident in a location + ///specifically allocated for it by LLDB in the + ///target process + EVIsProgramReference = 1 << 1, ///< This variable is a reference to a + ///(possibly invalid) area managed by the + ///target program + EVNeedsAllocation = 1 << 2, ///< Space for this variable has yet to be + ///allocated in the target process + EVIsFreezeDried = 1 << 3, ///< This variable's authoritative version is in + ///m_frozen_sp (for example, for + ///statically-computed results) + EVNeedsFreezeDry = + 1 << 4, ///< Copy from m_live_sp to m_frozen_sp during dematerialization + EVKeepInTarget = 1 << 5, ///< Keep the allocation after the expression is + ///complete rather than freeze drying its contents + ///and freeing it + EVTypeIsReference = 1 << 6, ///< The original type of this variable is a + ///reference, so materialize the value rather + ///than the location + EVUnknownType = 1 << 7, ///< This is a symbol of unknown type, and the type + ///must be resolved after parsing is complete + EVBareRegister = 1 << 8 ///< This variable is a direct reference to $pc or + ///some other entity. + }; + + typedef uint16_t FlagType; + + FlagType m_flags; // takes elements of Flags + + // these should be private + lldb::ValueObjectSP m_frozen_sp; + lldb::ValueObjectSP m_live_sp; + LLVMCastKind m_kind; +}; + +//---------------------------------------------------------------------- +/// @class ExpressionVariableList ExpressionVariable.h +/// "lldb/Expression/ExpressionVariable.h" +/// @brief A list of variable references. +/// +/// This class stores variables internally, acting as the permanent store. +//---------------------------------------------------------------------- +class ExpressionVariableList { +public: + //---------------------------------------------------------------------- + /// Implementation of methods in ExpressionVariableListBase + //---------------------------------------------------------------------- + size_t GetSize() { return m_variables.size(); } + + lldb::ExpressionVariableSP GetVariableAtIndex(size_t index) { + lldb::ExpressionVariableSP var_sp; + if (index < m_variables.size()) + var_sp = m_variables[index]; + return var_sp; + } + + size_t AddVariable(const lldb::ExpressionVariableSP &var_sp) { + m_variables.push_back(var_sp); + return m_variables.size() - 1; + } + + lldb::ExpressionVariableSP + AddNewlyConstructedVariable(ExpressionVariable *var) { + lldb::ExpressionVariableSP var_sp(var); + m_variables.push_back(var_sp); + return m_variables.back(); + } + + bool ContainsVariable(const lldb::ExpressionVariableSP &var_sp) { + const size_t size = m_variables.size(); + for (size_t index = 0; index < size; ++index) { + if (m_variables[index].get() == var_sp.get()) + return true; + } + return false; + } + + //---------------------------------------------------------------------- + /// Finds a variable by name in the list. + /// + /// @param[in] name + /// The name of the requested variable. + /// + /// @return + /// The variable requested, or nullptr if that variable is not in the + /// list. + //---------------------------------------------------------------------- + lldb::ExpressionVariableSP GetVariable(const ConstString &name) { + lldb::ExpressionVariableSP var_sp; + for (size_t index = 0, size = GetSize(); index < size; ++index) { + var_sp = GetVariableAtIndex(index); + if (var_sp->GetName() == name) + return var_sp; + } + var_sp.reset(); + return var_sp; + } + + lldb::ExpressionVariableSP GetVariable(llvm::StringRef name) { + if (name.empty()) + return nullptr; + + for (size_t index = 0, size = GetSize(); index < size; ++index) { + auto var_sp = GetVariableAtIndex(index); + llvm::StringRef var_name_str = var_sp->GetName().GetStringRef(); + if (var_name_str == name) + return var_sp; + } + return nullptr; + } + + void RemoveVariable(lldb::ExpressionVariableSP var_sp) { + for (std::vector::iterator + vi = m_variables.begin(), + ve = m_variables.end(); + vi != ve; ++vi) { + if (vi->get() == var_sp.get()) { + m_variables.erase(vi); + return; + } + } + } + + void Clear() { m_variables.clear(); } + +private: + std::vector m_variables; +}; + +class PersistentExpressionState : public ExpressionVariableList { +public: + //---------------------------------------------------------------------- + // See TypeSystem.h for how to add subclasses to this. + //---------------------------------------------------------------------- + enum LLVMCastKind { eKindClang, eKindSwift, eKindGo, kNumKinds }; + + LLVMCastKind getKind() const { return m_kind; } + + PersistentExpressionState(LLVMCastKind kind) : m_kind(kind) {} + + virtual ~PersistentExpressionState(); + + virtual lldb::ExpressionVariableSP + CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) = 0; + + virtual lldb::ExpressionVariableSP + CreatePersistentVariable(ExecutionContextScope *exe_scope, + const ConstString &name, const CompilerType &type, + lldb::ByteOrder byte_order, + uint32_t addr_byte_size) = 0; + + virtual ConstString GetNextPersistentVariableName() = 0; + + virtual void + RemovePersistentVariable(lldb::ExpressionVariableSP variable) = 0; + + virtual lldb::addr_t LookupSymbol(const ConstString &name); + + void RegisterExecutionUnit(lldb::IRExecutionUnitSP &execution_unit_sp); + +private: + LLVMCastKind m_kind; + + typedef std::set ExecutionUnitSet; + ExecutionUnitSet + m_execution_units; ///< The execution units that contain valuable symbols. + + typedef llvm::DenseMap SymbolMap; + SymbolMap + m_symbol_map; ///< The addresses of the symbols in m_execution_units. +}; + +} // namespace lldb_private + +#endif // liblldb_ExpressionVariable_h_ diff --git a/include/lldb/Expression/FunctionCaller.h b/include/lldb/Expression/FunctionCaller.h new file mode 100644 index 000000000..56305d518 --- /dev/null +++ b/include/lldb/Expression/FunctionCaller.h @@ -0,0 +1,391 @@ +//===-- FunctionCaller.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_FunctionCaller_h_ +#define liblldb_FunctionCaller_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Address.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/Expression.h" +#include "lldb/Expression/ExpressionParser.h" +#include "lldb/Symbol/CompilerType.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class FunctionCaller FunctionCaller.h "lldb/Expression/FunctionCaller.h" +/// @brief Encapsulates a function that can be called. +/// +/// A given FunctionCaller object can handle a single function signature. +/// Once constructed, it can set up any number of concurrent calls to +/// functions with that signature. +/// +/// It performs the call by synthesizing a structure that contains the pointer +/// to the function and the arguments that should be passed to that function, +/// and producing a special-purpose JIT-compiled function that accepts a void* +/// pointing to this struct as its only argument and calls the function in the +/// struct with the written arguments. This method lets Clang handle the +/// vagaries of function calling conventions. +/// +/// The simplest use of the FunctionCaller is to construct it with a +/// function representative of the signature you want to use, then call +/// ExecuteFunction(ExecutionContext &, Stream &, Value &). +/// +/// If you need to reuse the arguments for several calls, you can call +/// InsertFunction() followed by WriteFunctionArguments(), which will return +/// the location of the args struct for the wrapper function in args_addr_ref. +/// +/// If you need to call the function on the thread plan stack, you can also +/// call InsertFunction() followed by GetThreadPlanToCallFunction(). +/// +/// Any of the methods that take arg_addr_ptr or arg_addr_ref can be passed +/// a pointer set to LLDB_INVALID_ADDRESS and new structure will be allocated +/// and its address returned in that variable. +/// +/// Any of the methods that take arg_addr_ptr can be passed nullptr, and the +/// argument space will be managed for you. +//---------------------------------------------------------------------- +class FunctionCaller : public Expression { +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] exe_scope + /// An execution context scope that gets us at least a target and + /// process. + /// + /// @param[in] ast_context + /// The AST context to evaluate argument types in. + /// + /// @param[in] return_qualtype + /// An opaque Clang QualType for the function result. Should be + /// defined in ast_context. + /// + /// @param[in] function_address + /// The address of the function to call. + /// + /// @param[in] arg_value_list + /// The default values to use when calling this function. Can + /// be overridden using WriteFunctionArguments(). + //------------------------------------------------------------------ + FunctionCaller(ExecutionContextScope &exe_scope, + const CompilerType &return_type, + const Address &function_address, + const ValueList &arg_value_list, const char *name); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~FunctionCaller() override; + + //------------------------------------------------------------------ + /// Compile the wrapper function + /// + /// @param[in] thread_to_use_sp + /// Compilation might end up calling functions. Pass in the thread you + /// want the compilation to use. If you pass in an empty ThreadSP it will + /// use the currently selected thread. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report parser errors to. + /// + /// @return + /// The number of errors. + //------------------------------------------------------------------ + virtual unsigned CompileFunction(lldb::ThreadSP thread_to_use_sp, + DiagnosticManager &diagnostic_manager) = 0; + + //------------------------------------------------------------------ + /// Insert the default function wrapper and its default argument struct + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in,out] args_addr_ref + /// The address of the structure to write the arguments into. May + /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated + /// and args_addr_ref is pointed to it. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool InsertFunction(ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, + DiagnosticManager &diagnostic_manager); + + //------------------------------------------------------------------ + /// Insert the default function wrapper (using the JIT) + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool WriteFunctionWrapper(ExecutionContext &exe_ctx, + DiagnosticManager &diagnostic_manager); + + //------------------------------------------------------------------ + /// Insert the default function argument struct + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in,out] args_addr_ref + /// The address of the structure to write the arguments into. May + /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated + /// and args_addr_ref is pointed to it. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool WriteFunctionArguments(ExecutionContext &exe_ctx, + lldb::addr_t &args_addr_ref, + DiagnosticManager &diagnostic_manager); + + //------------------------------------------------------------------ + /// Insert an argument struct with a non-default function address and + /// non-default argument values + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in,out] args_addr_ref + /// The address of the structure to write the arguments into. May + /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated + /// and args_addr_ref is pointed at it. + /// + /// @param[in] arg_values + /// The values of the function's arguments. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report errors to. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool WriteFunctionArguments(ExecutionContext &exe_ctx, + lldb::addr_t &args_addr_ref, + ValueList &arg_values, + DiagnosticManager &diagnostic_manager); + + //------------------------------------------------------------------ + /// Run the function this FunctionCaller was created with. + /// + /// This is the full version. + /// + /// @param[in] exe_ctx + /// The thread & process in which this function will run. + /// + /// @param[in] args_addr_ptr + /// If nullptr, 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] diagnostic_manager + /// The diagnostic manager to report errors to. + /// + /// @param[in] options + /// The options for this expression execution. + /// + /// @param[out] results + /// The result value will be put here after running the function. + /// + /// @return + /// Returns one of the ExpressionResults enum indicating function call + /// status. + //------------------------------------------------------------------ + lldb::ExpressionResults + ExecuteFunction(ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, + const EvaluateExpressionOptions &options, + DiagnosticManager &diagnostic_manager, Value &results); + + //------------------------------------------------------------------ + /// Get a thread plan to run the function this FunctionCaller was created + /// with. + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] func_addr + /// The address of the function in the target process. + /// + /// @param[in] args_addr + /// The address of the argument struct. + /// + /// @param[in] diagnostic_manager + /// The diagnostic manager to report errors to. + /// + /// @param[in] stop_others + /// True if other threads should pause during execution. + /// + /// @param[in] unwind_on_error + /// True if the thread plan may simply be discarded if an error occurs. + /// + /// @return + /// A ThreadPlan shared pointer for executing the function. + //------------------------------------------------------------------ + lldb::ThreadPlanSP + GetThreadPlanToCallFunction(ExecutionContext &exe_ctx, lldb::addr_t args_addr, + const EvaluateExpressionOptions &options, + DiagnosticManager &diagnostic_manager); + + //------------------------------------------------------------------ + /// Get the result of the function from its struct + /// + /// @param[in] exe_ctx + /// The execution context to retrieve the result from. + /// + /// @param[in] args_addr + /// The address of the argument struct. + /// + /// @param[out] ret_value + /// The value returned by the function. + /// + /// @return + /// True on success; false otherwise. + //------------------------------------------------------------------ + bool FetchFunctionResults(ExecutionContext &exe_ctx, lldb::addr_t args_addr, + Value &ret_value); + + //------------------------------------------------------------------ + /// Deallocate the arguments structure + /// + /// @param[in] exe_ctx + /// The execution context to insert the function and its arguments + /// into. + /// + /// @param[in] args_addr + /// The address of the argument struct. + //------------------------------------------------------------------ + void DeallocateFunctionResults(ExecutionContext &exe_ctx, + lldb::addr_t args_addr); + + //------------------------------------------------------------------ + /// Interface for ClangExpression + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char *Text() override { return m_wrapper_function_text.c_str(); } + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + const char *FunctionName() override { + return m_wrapper_function_name.c_str(); + } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when registering + /// local variables. May be nullptr if the Expression doesn't care. + //------------------------------------------------------------------ + ExpressionVariableList *LocalVariables() { return nullptr; } + + //------------------------------------------------------------------ + /// Return true if validation code should be inserted into the + /// expression. + //------------------------------------------------------------------ + bool NeedsValidation() override { return false; } + + //------------------------------------------------------------------ + /// Return true if external variables in the expression should be + /// resolved. + //------------------------------------------------------------------ + bool NeedsVariableResolution() override { return false; } + + ValueList GetArgumentValues() const { return m_arg_values; } + +protected: + // Note: the parser needs to be destructed before the execution unit, so + // declare the execution unit first. + std::shared_ptr m_execution_unit_sp; + std::unique_ptr + m_parser; ///< The parser responsible for compiling the function. + ///< This will get made in CompileFunction, so it is + ///< safe to access it after that. + + lldb::ModuleWP m_jit_module_wp; + std::string + m_name; ///< The name of this clang function - for debugging purposes. + + Function *m_function_ptr; ///< The function we're going to call. May be + ///nullptr 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. + CompilerType m_function_return_type; ///< The opaque clang qual type for the + ///function return type. + + std::string m_wrapper_function_name; ///< The name of the wrapper function. + std::string + m_wrapper_function_text; ///< The contents of the wrapper function. + std::string m_wrapper_struct_name; ///< The name of the struct that contains + ///the target function address, arguments, + ///and result. + std::list m_wrapper_args_addrs; ///< The addresses of the + ///arguments to the wrapper + ///function. + + bool m_struct_valid; ///< True if the ASTStructExtractor has populated the + ///variables below. + + //------------------------------------------------------------------ + /// These values are populated by the ASTStructExtractor + size_t m_struct_size; ///< The size of the argument struct, in bytes. + std::vector + m_member_offsets; ///< The offset of each member in the struct, in bytes. + uint64_t m_return_size; ///< The size of the result variable, in bytes. + uint64_t m_return_offset; ///< The offset of the result variable in the + ///struct, in bytes. + //------------------------------------------------------------------ + + ValueList m_arg_values; ///< The default values of the arguments. + + bool m_compiled; ///< True if the wrapper function has already been parsed. + bool + m_JITted; ///< True if the wrapper function has already been JIT-compiled. +}; + +} // namespace lldb_private + +#endif // liblldb_FunctionCaller_h_ diff --git a/include/lldb/Expression/IRDynamicChecks.h b/include/lldb/Expression/IRDynamicChecks.h new file mode 100644 index 000000000..b793a6058 --- /dev/null +++ b/include/lldb/Expression/IRDynamicChecks.h @@ -0,0 +1,170 @@ +//===-- IRDynamicChecks.h ---------------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_IRDynamicChecks_h_ +#define liblldb_IRDynamicChecks_h_ + +#include "lldb/lldb-types.h" +#include "llvm/Pass.h" + +namespace llvm { +class BasicBlock; +class CallInst; +class Constant; +class Function; +class Instruction; +class Module; +class DataLayout; +class Value; +} + +namespace lldb_private { + +class ClangExpressionDeclMap; +class ExecutionContext; +class Stream; + +//---------------------------------------------------------------------- +/// @class DynamicCheckerFunctions IRDynamicChecks.h +/// "lldb/Expression/IRDynamicChecks.h" +/// @brief Encapsulates dynamic check functions used by expressions. +/// +/// Each of the utility functions encapsulated in this class is responsible +/// for validating some data that an expression is about to use. Examples are: +/// +/// a = *b; // check that b is a valid pointer +/// [b init]; // check that b is a valid object to send "init" to +/// +/// The class installs each checker function into the target process and +/// makes it available to IRDynamicChecks to use. +//---------------------------------------------------------------------- +class DynamicCheckerFunctions { +public: + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + DynamicCheckerFunctions(); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~DynamicCheckerFunctions(); + + //------------------------------------------------------------------ + /// Install the utility functions into a process. This binds the + /// instance of DynamicCheckerFunctions to that process. + /// + /// @param[in] diagnostic_manager + /// A diagnostic manager to report errors to. + /// + /// @param[in] exe_ctx + /// The execution context to install the functions into. + /// + /// @return + /// True on success; false on failure, or if the functions have + /// already been installed. + //------------------------------------------------------------------ + bool Install(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx); + + bool DoCheckersExplainStop(lldb::addr_t addr, Stream &message); + + std::unique_ptr m_valid_pointer_check; + std::unique_ptr m_objc_object_check; +}; + +//---------------------------------------------------------------------- +/// @class IRDynamicChecks IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h" +/// @brief Adds dynamic checks to a user-entered expression to reduce its +/// likelihood of crashing +/// +/// When an IR function is executed in the target process, it may cause +/// crashes or hangs by dereferencing NULL pointers, trying to call Objective-C +/// methods on objects that do not respond to them, and so forth. +/// +/// IRDynamicChecks adds calls to the functions in DynamicCheckerFunctions +/// to appropriate locations in an expression's IR. +//---------------------------------------------------------------------- +class IRDynamicChecks : public llvm::ModulePass { +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] checker_functions + /// The checker functions for the target process. + /// + /// @param[in] func_name + /// The name of the function to prepare for execution in the target. + /// + /// @param[in] decl_map + /// The mapping used to look up entities in the target process. In + /// this case, used to find objc_msgSend + //------------------------------------------------------------------ + IRDynamicChecks(DynamicCheckerFunctions &checker_functions, + const char *func_name = "$__lldb_expr"); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~IRDynamicChecks() override; + + //------------------------------------------------------------------ + /// Run this IR transformer on a single module + /// + /// @param[in] M + /// The module to run on. This module is searched for the function + /// $__lldb_expr, and that function is passed to the passes one by + /// one. + /// + /// @return + /// True on success; false otherwise + //------------------------------------------------------------------ + bool runOnModule(llvm::Module &M) override; + + //------------------------------------------------------------------ + /// Interface stub + //------------------------------------------------------------------ + void assignPassManager( + llvm::PMStack &PMS, + llvm::PassManagerType T = llvm::PMT_ModulePassManager) override; + + //------------------------------------------------------------------ + /// Returns PMT_ModulePassManager + //------------------------------------------------------------------ + llvm::PassManagerType getPotentialPassManagerType() const override; + +private: + //------------------------------------------------------------------ + /// A basic block-level pass to find all pointer dereferences and + /// validate them before use. + //------------------------------------------------------------------ + + //------------------------------------------------------------------ + /// The top-level pass implementation + /// + /// @param[in] M + /// The module currently being processed. + /// + /// @param[in] BB + /// The basic block currently being processed. + /// + /// @return + /// True on success; false otherwise + //------------------------------------------------------------------ + bool FindDataLoads(llvm::Module &M, llvm::BasicBlock &BB); + + std::string m_func_name; ///< The name of the function to add checks to + DynamicCheckerFunctions + &m_checker_functions; ///< The checker functions for the process +}; + +} // namespace lldb_private + +#endif // liblldb_IRDynamicChecks_h_ diff --git a/include/lldb/Expression/IRExecutionUnit.h b/include/lldb/Expression/IRExecutionUnit.h new file mode 100644 index 000000000..b0b4d7a5c --- /dev/null +++ b/include/lldb/Expression/IRExecutionUnit.h @@ -0,0 +1,437 @@ +//===-- IRExecutionUnit.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_IRExecutionUnit_h_ +#define liblldb_IRExecutionUnit_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/Module.h" + +// Project includes +#include "lldb/Expression/IRMemoryMap.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +namespace llvm { + +class Module; +class ExecutionEngine; +class ObjectCache; + +} // namespace llvm + +namespace lldb_private { + +class Status; + +//---------------------------------------------------------------------- +/// @class IRExecutionUnit IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h" +/// @brief Contains the IR and, optionally, JIT-compiled code for a module. +/// +/// This class encapsulates the compiled version of an expression, in IR +/// form (for interpretation purposes) and in raw machine code form (for +/// execution in the target). +/// +/// This object wraps an IR module that comes from the expression parser, +/// and knows how to use the JIT to make it into executable code. It can +/// then be used as input to the IR interpreter, or the address of the +/// executable code can be passed to a thread plan to run in the target. +/// +/// This class creates a subclass of LLVM's SectionMemoryManager, because that +/// is +/// how the JIT emits code. Because LLDB needs to move JIT-compiled code +/// into the target process, the IRExecutionUnit knows how to copy the +/// emitted code into the target process. +//---------------------------------------------------------------------- +class IRExecutionUnit : public std::enable_shared_from_this, + public IRMemoryMap, + public ObjectFileJITDelegate { +public: + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + IRExecutionUnit(std::unique_ptr &context_ap, + std::unique_ptr &module_ap, ConstString &name, + const lldb::TargetSP &target_sp, const SymbolContext &sym_ctx, + std::vector &cpu_features); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~IRExecutionUnit() override; + + ConstString GetFunctionName() { return m_name; } + + llvm::Module *GetModule() { return m_module; } + + llvm::Function *GetFunction() { + return ((m_module != nullptr) ? m_module->getFunction(m_name.AsCString()) + : nullptr); + } + + void GetRunnableInfo(Status &error, lldb::addr_t &func_addr, + lldb::addr_t &func_end); + + //------------------------------------------------------------------ + /// Accessors for IRForTarget and other clients that may want binary + /// data placed on their behalf. The binary data is owned by the + /// IRExecutionUnit unless the client explicitly chooses to free it. + //------------------------------------------------------------------ + + lldb::addr_t WriteNow(const uint8_t *bytes, size_t size, Status &error); + + void FreeNow(lldb::addr_t allocation); + + //------------------------------------------------------------------ + /// ObjectFileJITDelegate overrides + //------------------------------------------------------------------ + lldb::ByteOrder GetByteOrder() const override; + + uint32_t GetAddressByteSize() const override; + + void PopulateSymtab(lldb_private::ObjectFile *obj_file, + lldb_private::Symtab &symtab) override; + + void PopulateSectionList(lldb_private::ObjectFile *obj_file, + lldb_private::SectionList §ion_list) override; + + bool GetArchitecture(lldb_private::ArchSpec &arch) override; + + lldb::ModuleSP GetJITModule(); + + lldb::addr_t FindSymbol(const ConstString &name); + + void GetStaticInitializers(std::vector &static_initializers); + + //---------------------------------------------------------------------- + /// @class JittedFunction IRExecutionUnit.h + /// "lldb/Expression/IRExecutionUnit.h" + /// @brief Encapsulates a single function that has been generated by the JIT. + /// + /// Functions that have been generated by the JIT are first resident in the + /// local process, and then placed in the target process. JittedFunction + /// represents a function possibly resident in both. + //---------------------------------------------------------------------- + struct JittedEntity { + ConstString m_name; ///< The function's name + lldb::addr_t m_local_addr; ///< The address of the function in LLDB's memory + lldb::addr_t + m_remote_addr; ///< The address of the function in the target's memory + + //------------------------------------------------------------------ + /// Constructor + /// + /// Initializes class variabes. + /// + /// @param[in] name + /// The name of the function. + /// + /// @param[in] local_addr + /// The address of the function in LLDB, or LLDB_INVALID_ADDRESS if + /// it is not present in LLDB's memory. + /// + /// @param[in] remote_addr + /// The address of the function in the target, or LLDB_INVALID_ADDRESS + /// if it is not present in the target's memory. + //------------------------------------------------------------------ + JittedEntity(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) {} + }; + + struct JittedFunction : JittedEntity { + bool m_external; + JittedFunction(const char *name, bool external, + lldb::addr_t local_addr = LLDB_INVALID_ADDRESS, + lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) + : JittedEntity(name, local_addr, remote_addr), m_external(external) {} + }; + + struct JittedGlobalVariable : JittedEntity { + JittedGlobalVariable(const char *name, + lldb::addr_t local_addr = LLDB_INVALID_ADDRESS, + lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) + : JittedEntity(name, local_addr, remote_addr) {} + }; + + const std::vector &GetJittedFunctions() { + return m_jitted_functions; + } + + const std::vector &GetJittedGlobalVariables() { + return m_jitted_global_variables; + } + +private: + //------------------------------------------------------------------ + /// Look up the object in m_address_map that contains a given address, + /// find where it was copied to, and return the remote address at the + /// same offset into the copied entity + /// + /// @param[in] local_address + /// The address in the debugger. + /// + /// @return + /// The address in the target process. + //------------------------------------------------------------------ + lldb::addr_t GetRemoteAddressForLocal(lldb::addr_t local_address); + + //------------------------------------------------------------------ + /// Look up the object in m_address_map that contains a given address, + /// find where it was copied to, and return its address range in the + /// target process + /// + /// @param[in] local_address + /// The address in the debugger. + /// + /// @return + /// The range of the containing object in the target process. + //------------------------------------------------------------------ + typedef std::pair AddrRange; + AddrRange GetRemoteRangeForLocal(lldb::addr_t local_address); + + //------------------------------------------------------------------ + /// Commit all allocations to the process and record where they were stored. + /// + /// @param[in] process + /// The process to allocate memory in. + /// + /// @return + /// True <=> all allocations were performed successfully. + /// This method will attempt to free allocated memory if the + /// operation fails. + //------------------------------------------------------------------ + bool CommitAllocations(lldb::ProcessSP &process_sp); + + //------------------------------------------------------------------ + /// Report all committed allocations to the execution engine. + /// + /// @param[in] engine + /// The execution engine to notify. + //------------------------------------------------------------------ + void ReportAllocations(llvm::ExecutionEngine &engine); + + //------------------------------------------------------------------ + /// Write the contents of all allocations to the process. + /// + /// @param[in] local_address + /// The process containing the allocations. + /// + /// @return + /// True <=> all allocations were performed successfully. + //------------------------------------------------------------------ + bool WriteData(lldb::ProcessSP &process_sp); + + Status DisassembleFunction(Stream &stream, lldb::ProcessSP &process_sp); + + struct SearchSpec; + + void CollectCandidateCNames(std::vector &C_specs, + const ConstString &name); + + void CollectCandidateCPlusPlusNames(std::vector &CPP_specs, + const std::vector &C_specs, + const SymbolContext &sc); + + void CollectFallbackNames(std::vector &fallback_specs, + const std::vector &C_specs); + + lldb::addr_t FindInSymbols(const std::vector &specs, + const lldb_private::SymbolContext &sc); + + lldb::addr_t FindInRuntimes(const std::vector &specs, + const lldb_private::SymbolContext &sc); + + lldb::addr_t FindInUserDefinedSymbols(const std::vector &specs, + const lldb_private::SymbolContext &sc); + + void ReportSymbolLookupError(const ConstString &name); + + class MemoryManager : public llvm::SectionMemoryManager { + public: + MemoryManager(IRExecutionUnit &parent); + + ~MemoryManager() override; + + //------------------------------------------------------------------ + /// Allocate space for executable code, and add it to the + /// m_spaceBlocks map + /// + /// @param[in] Size + /// The size of the area. + /// + /// @param[in] Alignment + /// The required alignment of the area. + /// + /// @param[in] SectionID + /// A unique identifier for the section. + /// + /// @return + /// Allocated space. + //------------------------------------------------------------------ + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + llvm::StringRef SectionName) override; + + //------------------------------------------------------------------ + /// Allocate space for data, and add it to the m_spaceBlocks map + /// + /// @param[in] Size + /// The size of the area. + /// + /// @param[in] Alignment + /// The required alignment of the area. + /// + /// @param[in] SectionID + /// A unique identifier for the section. + /// + /// @param[in] IsReadOnly + /// Flag indicating the section is read-only. + /// + /// @return + /// Allocated space. + //------------------------------------------------------------------ + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + llvm::StringRef SectionName, + bool IsReadOnly) override; + + //------------------------------------------------------------------ + /// Called when object loading is complete and section page + /// permissions can be applied. Currently unimplemented for LLDB. + /// + /// @param[out] ErrMsg + /// The error that prevented the page protection from succeeding. + /// + /// @return + /// True in case of failure, false in case of success. + //------------------------------------------------------------------ + bool finalizeMemory(std::string *ErrMsg) override { + // TODO: Ensure that the instruction cache is flushed because + // relocations are updated by dy-load. See: + // sys::Memory::InvalidateInstructionCache + // llvm::SectionMemoryManager + return false; + } + + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) override {} + + uint64_t getSymbolAddress(const std::string &Name) override; + + void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) override; + + private: + std::unique_ptr m_default_mm_ap; ///< The memory + ///allocator to use + ///in actually + ///creating space. + ///All calls are + ///passed through to + ///it. + IRExecutionUnit &m_parent; ///< The execution unit this is a proxy for. + }; + + static const unsigned eSectionIDInvalid = (unsigned)-1; + + //---------------------------------------------------------------------- + /// @class AllocationRecord IRExecutionUnit.h + /// "lldb/Expression/IRExecutionUnit.h" + /// @brief Encapsulates a single allocation request made by the JIT. + /// + /// Allocations made by the JIT are first queued up and then applied in + /// bulk to the underlying process. + //---------------------------------------------------------------------- + enum class AllocationKind { Stub, Code, Data, Global, Bytes }; + + static lldb::SectionType + GetSectionTypeFromSectionName(const llvm::StringRef &name, + AllocationKind alloc_kind); + + struct AllocationRecord { + std::string m_name; + lldb::addr_t m_process_address; + uintptr_t m_host_address; + uint32_t m_permissions; + lldb::SectionType m_sect_type; + size_t m_size; + unsigned m_alignment; + unsigned m_section_id; + + AllocationRecord(uintptr_t host_address, uint32_t permissions, + lldb::SectionType sect_type, size_t size, + unsigned alignment, unsigned section_id, const char *name) + : m_name(), m_process_address(LLDB_INVALID_ADDRESS), + m_host_address(host_address), m_permissions(permissions), + m_sect_type(sect_type), m_size(size), m_alignment(alignment), + m_section_id(section_id) { + if (name && name[0]) + m_name = name; + } + + void dump(Log *log); + }; + + bool CommitOneAllocation(lldb::ProcessSP &process_sp, Status &error, + AllocationRecord &record); + + typedef std::vector RecordVector; + RecordVector m_records; + + std::unique_ptr m_context_ap; + std::unique_ptr m_execution_engine_ap; + std::unique_ptr m_object_cache_ap; + std::unique_ptr + m_module_ap; ///< Holder for the module until it's been handed off + llvm::Module *m_module; ///< Owned by the execution engine + std::vector m_cpu_features; + std::vector m_jitted_functions; ///< A vector of all functions + ///that have been JITted into + ///machine code + std::vector m_jitted_global_variables; ///< A vector of + ///all functions + ///that have been + ///JITted into + ///machine code + const ConstString m_name; + SymbolContext m_sym_ctx; ///< Used for symbol lookups + std::vector m_failed_lookups; + + std::atomic m_did_jit; + + lldb::addr_t m_function_load_addr; + lldb::addr_t m_function_end_load_addr; + + bool m_strip_underscore; ///< True for platforms where global symbols have a _ + ///prefix + bool m_reported_allocations; ///< True after allocations have been reported. + ///It is possible that + ///< sections will be allocated when this is true, in which case they weren't + ///< depended on by any function. (Top-level code defining a variable, but + ///< defining no functions using that variable, would do this.) If this + ///< is true, any allocations need to be committed immediately -- no + ///< opportunity for relocation. +}; + +} // namespace lldb_private + +#endif // liblldb_IRExecutionUnit_h_ diff --git a/include/lldb/Expression/IRInterpreter.h b/include/lldb/Expression/IRInterpreter.h new file mode 100644 index 000000000..36e03c6fc --- /dev/null +++ b/include/lldb/Expression/IRInterpreter.h @@ -0,0 +1,58 @@ +//===-- IRInterpreter.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_IRInterpreter_h_ +#define liblldb_IRInterpreter_h_ + +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Stream.h" +#include "lldb/lldb-public.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Pass.h" + +namespace llvm { +class Function; +class Module; +} + +namespace lldb_private { + +class ClangExpressionDeclMap; +class IRMemoryMap; +} + +//---------------------------------------------------------------------- +/// @class IRInterpreter IRInterpreter.h "lldb/Expression/IRInterpreter.h" +/// @brief Attempt to interpret the function's code if it does not require +/// running the target. +/// +/// In some cases, the IR for an expression can be evaluated entirely +/// in the debugger, manipulating variables but not executing any code +/// in the target. The IRInterpreter attempts to do this. +//---------------------------------------------------------------------- +class IRInterpreter { +public: + static bool CanInterpret(llvm::Module &module, llvm::Function &function, + lldb_private::Status &error, + const bool support_function_calls); + + static bool Interpret(llvm::Module &module, llvm::Function &function, + llvm::ArrayRef args, + lldb_private::IRExecutionUnit &execution_unit, + lldb_private::Status &error, + lldb::addr_t stack_frame_bottom, + lldb::addr_t stack_frame_top, + lldb_private::ExecutionContext &exe_ctx); + +private: + static bool supportsFunction(llvm::Function &llvm_function, + lldb_private::Status &err); +}; + +#endif diff --git a/include/lldb/Expression/IRMemoryMap.h b/include/lldb/Expression/IRMemoryMap.h new file mode 100644 index 000000000..abb5cd745 --- /dev/null +++ b/include/lldb/Expression/IRMemoryMap.h @@ -0,0 +1,139 @@ +//===-- IRExecutionUnit.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_IRMemoryMap_h_ +#define lldb_IRMemoryMap_h_ + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-public.h" + +#include + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class IRMemoryMap IRMemoryMap.h "lldb/Expression/IRMemoryMap.h" +/// @brief Encapsulates memory that may exist in the process but must +/// also be available in the host process. +/// +/// This class encapsulates a group of memory objects that must be readable +/// or writable from the host process regardless of whether the process +/// exists. This allows the IR interpreter as well as JITted code to access +/// the same memory. All allocations made by this class are represented as +/// disjoint intervals. +/// +/// Point queries against this group of memory objects can be made by the +/// address in the tar at which they reside. If the inferior does not +/// exist, allocations still get made-up addresses. If an inferior appears +/// at some point, then those addresses need to be re-mapped. +//---------------------------------------------------------------------- +class IRMemoryMap { +public: + IRMemoryMap(lldb::TargetSP target_sp); + ~IRMemoryMap(); + + enum AllocationPolicy { + eAllocationPolicyInvalid = + 0, ///< It is an error for an allocation to have this policy. + eAllocationPolicyHostOnly, ///< This allocation was created in the host and + ///will never make it into the process. + ///< It is an error to create other types of allocations while such + ///allocations exist. + eAllocationPolicyMirror, ///< The intent is that this allocation exist both + ///in the host and the process and have + ///< the same content in both. + eAllocationPolicyProcessOnly ///< The intent is that this allocation exist + ///only in the process. + }; + + lldb::addr_t Malloc(size_t size, uint8_t alignment, uint32_t permissions, + AllocationPolicy policy, bool zero_memory, Status &error); + void Leak(lldb::addr_t process_address, Status &error); + void Free(lldb::addr_t process_address, Status &error); + + void WriteMemory(lldb::addr_t process_address, const uint8_t *bytes, + size_t size, Status &error); + void WriteScalarToMemory(lldb::addr_t process_address, Scalar &scalar, + size_t size, Status &error); + void WritePointerToMemory(lldb::addr_t process_address, lldb::addr_t address, + Status &error); + void ReadMemory(uint8_t *bytes, lldb::addr_t process_address, size_t size, + Status &error); + void ReadScalarFromMemory(Scalar &scalar, lldb::addr_t process_address, + size_t size, Status &error); + void ReadPointerFromMemory(lldb::addr_t *address, + lldb::addr_t process_address, Status &error); + bool GetAllocSize(lldb::addr_t address, size_t &size); + void GetMemoryData(DataExtractor &extractor, lldb::addr_t process_address, + size_t size, Status &error); + + lldb::ByteOrder GetByteOrder(); + uint32_t GetAddressByteSize(); + + // This function can return NULL. + ExecutionContextScope *GetBestExecutionContextScope() const; + + lldb::TargetSP GetTarget() { return m_target_wp.lock(); } + +protected: + // This function should only be used if you know you are using the JIT. + // Any other cases should use GetBestExecutionContextScope(). + + lldb::ProcessWP &GetProcessWP() { return m_process_wp; } + +private: + struct Allocation { + lldb::addr_t + m_process_alloc; ///< The (unaligned) base for the remote allocation + lldb::addr_t + m_process_start; ///< The base address of the allocation in the process + size_t m_size; ///< The size of the requested allocation + uint32_t m_permissions; ///< The access permissions on the memory in the + ///process. In the host, the memory is always + ///read/write. + uint8_t m_alignment; ///< The alignment of the requested allocation + DataBufferHeap m_data; + + ///< Flags + AllocationPolicy m_policy; + bool m_leak; + + public: + Allocation(lldb::addr_t process_alloc, lldb::addr_t process_start, + size_t size, uint32_t permissions, uint8_t alignment, + AllocationPolicy m_policy); + + Allocation() + : m_process_alloc(LLDB_INVALID_ADDRESS), + m_process_start(LLDB_INVALID_ADDRESS), m_size(0), m_permissions(0), + m_alignment(0), m_data(), m_policy(eAllocationPolicyInvalid), + m_leak(false) {} + }; + + lldb::ProcessWP m_process_wp; + lldb::TargetWP m_target_wp; + typedef std::map AllocationMap; + AllocationMap m_allocations; + + lldb::addr_t FindSpace(size_t size); + bool ContainsHostOnlyAllocations(); + AllocationMap::iterator FindAllocation(lldb::addr_t addr, size_t size); + + // Returns true if the given allocation intersects any allocation in the + // memory map. + bool IntersectsAllocation(lldb::addr_t addr, size_t size) const; + + // Returns true if the two given allocations intersect each other. + static bool AllocationsIntersect(lldb::addr_t addr1, size_t size1, + lldb::addr_t addr2, size_t size2); +}; +} + +#endif diff --git a/include/lldb/Expression/LLVMUserExpression.h b/include/lldb/Expression/LLVMUserExpression.h new file mode 100644 index 000000000..745d413e0 --- /dev/null +++ b/include/lldb/Expression/LLVMUserExpression.h @@ -0,0 +1,138 @@ +//===-- LLVMUserExpression.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_LLVMUserExpression_h +#define liblldb_LLVMUserExpression_h + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +#include "llvm/IR/LegacyPassManager.h" + +// Project includes +#include "lldb/Expression/UserExpression.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class LLVMUserExpression LLVMUserExpression.h +/// "lldb/Expression/LLVMUserExpression.h" +/// @brief Encapsulates a one-time expression for use in lldb. +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. LLVMUserExpression is a virtual base +/// class that encapsulates the objects needed to parse and JIT an expression. +/// The actual parsing part will be provided by the specific implementations +/// of LLVMUserExpression - which will be vended through the appropriate +/// TypeSystem. +//---------------------------------------------------------------------- +class LLVMUserExpression : public UserExpression { +public: + // The IRPasses struct is filled in by a runtime after an expression is + // compiled and can be used to to run + // fixups/analysis passes as required. EarlyPasses are run on the generated + // module before lldb runs its own IR + // fixups and inserts instrumentation code/pointer checks. LatePasses are run + // after the module has been processed by + // llvm, before the module is assembled and run in the ThreadPlan. + struct IRPasses { + IRPasses() : EarlyPasses(nullptr), LatePasses(nullptr){}; + std::shared_ptr EarlyPasses; + std::shared_ptr LatePasses; + }; + + LLVMUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, + llvm::StringRef prefix, lldb::LanguageType language, + ResultType desired_type, + const EvaluateExpressionOptions &options); + ~LLVMUserExpression() override; + + bool FinalizeJITExecution( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override; + + bool CanInterpret() override { return m_can_interpret; } + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char *Text() override { return m_transformed_text.c_str(); } + + lldb::ModuleSP GetJITModule() override; + +protected: + lldb::ExpressionResults + DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) override; + + virtual void ScanContext(ExecutionContext &exe_ctx, + lldb_private::Status &err) = 0; + + bool PrepareToExecuteJITExpression(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + lldb::addr_t &struct_address); + + virtual bool AddArguments(ExecutionContext &exe_ctx, + std::vector &args, + lldb::addr_t struct_address, + DiagnosticManager &diagnostic_manager) = 0; + + lldb::addr_t + m_stack_frame_bottom; ///< The bottom of the allocated stack frame. + lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame. + + bool m_allow_cxx; ///< True if the language allows C++. + bool m_allow_objc; ///< True if the language allows Objective-C. + std::string + m_transformed_text; ///< The text of the expression, as send to the parser + + std::shared_ptr + m_execution_unit_sp; ///< The execution unit the expression is stored in. + std::unique_ptr m_materializer_ap; ///< The materializer to use + ///when running the + ///expression. + lldb::ModuleWP m_jit_module_wp; + bool m_enforce_valid_object; ///< True if the expression parser should enforce + ///the presence of a valid class pointer + /// in order to generate the expression as a method. + bool m_in_cplusplus_method; ///< True if the expression is compiled as a C++ + ///member function (true if it was parsed + /// when exe_ctx was in a C++ method). + bool m_in_objectivec_method; ///< True if the expression is compiled as an + ///Objective-C method (true if it was parsed + /// when exe_ctx was in an Objective-C method). + bool m_in_static_method; ///< True if the expression is compiled as a static + ///(or class) method (currently true if it + /// was parsed when exe_ctx was in an Objective-C class method). + bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and + ///passed in. False if the expression + /// doesn't really use them and they can be NULL. + bool m_const_object; ///< True if "this" is const. + Target *m_target; ///< The target for storing persistent data like types and + ///variables. + + bool m_can_interpret; ///< True if the expression could be evaluated + ///statically; false otherwise. + lldb::addr_t m_materialized_address; ///< The address at which the arguments + ///to the expression have been + ///materialized. + Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer. +}; + +} // namespace lldb_private +#endif diff --git a/include/lldb/Expression/Materializer.h b/include/lldb/Expression/Materializer.h new file mode 100644 index 000000000..b86bc656d --- /dev/null +++ b/include/lldb/Expression/Materializer.h @@ -0,0 +1,144 @@ +//===-- Materializer.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Materializer_h +#define liblldb_Materializer_h + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Expression/IRMemoryMap.h" +#include "lldb/Symbol/TaggedASTType.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-private-types.h" + +namespace lldb_private { + +class Materializer { +public: + Materializer(); + ~Materializer(); + + class Dematerializer { + public: + Dematerializer() + : m_materializer(nullptr), m_map(nullptr), + m_process_address(LLDB_INVALID_ADDRESS) {} + + ~Dematerializer() { Wipe(); } + + void Dematerialize(Status &err, lldb::addr_t frame_top, + lldb::addr_t frame_bottom); + + void Wipe(); + + bool IsValid() { + return m_materializer && m_map && + (m_process_address != LLDB_INVALID_ADDRESS); + } + + private: + friend class Materializer; + + Dematerializer(Materializer &materializer, lldb::StackFrameSP &frame_sp, + IRMemoryMap &map, lldb::addr_t process_address) + : m_materializer(&materializer), m_map(&map), + m_process_address(process_address) { + if (frame_sp) { + m_thread_wp = frame_sp->GetThread(); + m_stack_id = frame_sp->GetStackID(); + } + } + + Materializer *m_materializer; + lldb::ThreadWP m_thread_wp; + StackID m_stack_id; + IRMemoryMap *m_map; + lldb::addr_t m_process_address; + }; + + typedef std::shared_ptr DematerializerSP; + typedef std::weak_ptr DematerializerWP; + + DematerializerSP Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, + lldb::addr_t process_address, Status &err); + + class PersistentVariableDelegate { + public: + virtual ~PersistentVariableDelegate(); + virtual ConstString GetName() = 0; + virtual void DidDematerialize(lldb::ExpressionVariableSP &variable) = 0; + }; + + uint32_t + AddPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, + PersistentVariableDelegate *delegate, Status &err); + uint32_t AddVariable(lldb::VariableSP &variable_sp, Status &err); + uint32_t AddResultVariable(const CompilerType &type, bool is_lvalue, + bool keep_in_memory, + PersistentVariableDelegate *delegate, Status &err); + uint32_t AddSymbol(const Symbol &symbol_sp, Status &err); + uint32_t AddRegister(const RegisterInfo ®ister_info, Status &err); + + uint32_t GetStructAlignment() { return m_struct_alignment; } + + uint32_t GetStructByteSize() { return m_current_offset; } + + class Entity { + public: + Entity() : m_alignment(1), m_size(0), m_offset(0) {} + + virtual ~Entity() = default; + + virtual void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, + lldb::addr_t process_address, Status &err) = 0; + virtual void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, + lldb::addr_t process_address, + lldb::addr_t frame_top, + lldb::addr_t frame_bottom, Status &err) = 0; + virtual void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, + Log *log) = 0; + virtual void Wipe(IRMemoryMap &map, lldb::addr_t process_address) = 0; + + uint32_t GetAlignment() { return m_alignment; } + + uint32_t GetSize() { return m_size; } + + uint32_t GetOffset() { return m_offset; } + + void SetOffset(uint32_t offset) { m_offset = offset; } + + protected: + void SetSizeAndAlignmentFromType(CompilerType &type); + + uint32_t m_alignment; + uint32_t m_size; + uint32_t m_offset; + }; + +private: + uint32_t AddStructMember(Entity &entity); + + typedef std::unique_ptr EntityUP; + typedef std::vector EntityVector; + + DematerializerWP m_dematerializer_wp; + EntityVector m_entities; + uint32_t m_current_offset; + uint32_t m_struct_alignment; +}; + +} // namespace lldb_private + +#endif // liblldb_Materializer_h diff --git a/include/lldb/Expression/REPL.h b/include/lldb/Expression/REPL.h new file mode 100644 index 000000000..0c1e97fec --- /dev/null +++ b/include/lldb/Expression/REPL.h @@ -0,0 +1,176 @@ +//===-- REPL.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_REPL_h +#define lldb_REPL_h + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/../../source/Commands/CommandObjectExpression.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" + +namespace lldb_private { + +class REPL : public IOHandlerDelegate { +public: + //---------------------------------------------------------------------- + // See TypeSystem.h for how to add subclasses to this. + //---------------------------------------------------------------------- + enum LLVMCastKind { eKindClang, eKindSwift, eKindGo, kNumKinds }; + + LLVMCastKind getKind() const { return m_kind; } + + REPL(LLVMCastKind kind, Target &target); + + ~REPL() override; + + //------------------------------------------------------------------ + /// Get a REPL with an existing target (or, failing that, a debugger to use), + /// and (optional) extra arguments for the compiler. + /// + /// @param[out] error + /// If this language is supported but the REPL couldn't be created, this + /// error is populated with the reason. + /// + /// @param[in] language + /// The language to create a REPL for. + /// + /// @param[in] debugger + /// If provided, and target is nullptr, the debugger to use when setting + /// up a top-level REPL. + /// + /// @param[in] target + /// If provided, the target to put the REPL inside. + /// + /// @param[in] repl_options + /// If provided, additional options for the compiler when parsing REPL + /// expressions. + /// + /// @return + /// The range of the containing object in the target process. + //------------------------------------------------------------------ + static lldb::REPLSP Create(Status &Status, lldb::LanguageType language, + Debugger *debugger, Target *target, + const char *repl_options); + + void SetFormatOptions(const OptionGroupFormat &options) { + m_format_options = options; + } + + void + SetValueObjectDisplayOptions(const OptionGroupValueObjectDisplay &options) { + m_varobj_options = options; + } + + void + SetCommandOptions(const CommandObjectExpression::CommandOptions &options) { + m_command_options = options; + } + + void SetCompilerOptions(const char *options) { + if (options) + m_compiler_options = options; + } + + lldb::IOHandlerSP GetIOHandler(); + + Status RunLoop(); + + //------------------------------------------------------------------ + // IOHandler::Delegate functions + //------------------------------------------------------------------ + void IOHandlerActivated(IOHandler &io_handler) override; + + bool IOHandlerInterrupt(IOHandler &io_handler) override; + + void IOHandlerInputInterrupted(IOHandler &io_handler, + std::string &line) override; + + const char *IOHandlerGetFixIndentationCharacters() override; + + ConstString IOHandlerGetControlSequence(char ch) override; + + const char *IOHandlerGetCommandPrefix() override; + + const char *IOHandlerGetHelpPrologue() override; + + bool IOHandlerIsInputComplete(IOHandler &io_handler, + StringList &lines) override; + + int IOHandlerFixIndentation(IOHandler &io_handler, const StringList &lines, + int cursor_position) override; + + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &line) override; + + int IOHandlerComplete(IOHandler &io_handler, const char *current_line, + const char *cursor, const char *last_char, + int skip_first_n_matches, int max_matches, + StringList &matches) override; + +protected: + static int CalculateActualIndentation(const StringList &lines); + + //---------------------------------------------------------------------- + // Subclasses should override these functions to implement a functional REPL. + //---------------------------------------------------------------------- + + virtual Status DoInitialization() = 0; + + virtual ConstString GetSourceFileBasename() = 0; + + virtual const char *GetAutoIndentCharacters() = 0; + + virtual bool SourceIsComplete(const std::string &source) = 0; + + virtual lldb::offset_t GetDesiredIndentation( + const StringList &lines, int cursor_position, + int tab_size) = 0; // LLDB_INVALID_OFFSET means no change + + virtual lldb::LanguageType GetLanguage() = 0; + + virtual bool PrintOneVariable(Debugger &debugger, + lldb::StreamFileSP &output_sp, + lldb::ValueObjectSP &valobj_sp, + ExpressionVariable *var = nullptr) = 0; + + virtual int CompleteCode(const std::string ¤t_code, + StringList &matches) = 0; + + OptionGroupFormat m_format_options = OptionGroupFormat(lldb::eFormatDefault); + OptionGroupValueObjectDisplay m_varobj_options; + CommandObjectExpression::CommandOptions m_command_options; + std::string m_compiler_options; + + bool m_enable_auto_indent = true; + std::string m_indent_str; // Use this string for each level of indentation + std::string m_current_indent_str; + uint32_t m_current_indent_level = 0; + + std::string m_repl_source_path; + bool m_dedicated_repl_mode = false; + + StringList m_code; // All accumulated REPL statements are saved here + + Target &m_target; + lldb::IOHandlerSP m_io_handler_sp; + LLVMCastKind m_kind; + +private: + std::string GetSourcePath(); +}; + +} // namespace lldb_private + +#endif // lldb_REPL_h diff --git a/include/lldb/Expression/UserExpression.h b/include/lldb/Expression/UserExpression.h new file mode 100644 index 000000000..ced5cb2bf --- /dev/null +++ b/include/lldb/Expression/UserExpression.h @@ -0,0 +1,314 @@ +//===-- UserExpression.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UserExpression_h_ +#define liblldb_UserExpression_h_ + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Address.h" +#include "lldb/Expression/Expression.h" +#include "lldb/Expression/Materializer.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class UserExpression UserExpression.h "lldb/Expression/UserExpression.h" +/// @brief Encapsulates a one-time expression for use in lldb. +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. UserExpression is a virtual base +/// class that encapsulates the objects needed to parse and interpret or +/// JIT an expression. The actual parsing part will be provided by the specific +/// implementations of UserExpression - which will be vended through the +/// appropriate TypeSystem. +//---------------------------------------------------------------------- +class UserExpression : public Expression { +public: + enum { kDefaultTimeout = 500000u }; + + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] expr + /// The expression to parse. + /// + /// @param[in] expr_prefix + /// If non-nullptr, a C string containing translation-unit level + /// definitions to be included when the expression is parsed. + /// + /// @param[in] language + /// If not eLanguageTypeUnknown, a language to use when parsing + /// the expression. Currently restricted to those languages + /// supported by Clang. + /// + /// @param[in] desired_type + /// If not eResultTypeAny, the type to use for the expression + /// result. + //------------------------------------------------------------------ + UserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, + llvm::StringRef prefix, lldb::LanguageType language, + ResultType desired_type, + const EvaluateExpressionOptions &options); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~UserExpression() override; + + //------------------------------------------------------------------ + /// Parse the expression + /// + /// @param[in] diagnostic_manager + /// A diagnostic manager to report parse errors and warnings to. + /// + /// @param[in] exe_ctx + /// The execution context to use when looking up entities that + /// are needed for parsing (locations of functions, types of + /// variables, persistent variables, etc.) + /// + /// @param[in] execution_policy + /// Determines whether interpretation is possible or mandatory. + /// + /// @param[in] keep_result_in_memory + /// True if the resulting persistent variable should reside in + /// target memory, if applicable. + /// + /// @return + /// True on success (no errors); false otherwise. + //------------------------------------------------------------------ + virtual bool Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) = 0; + + virtual bool CanInterpret() = 0; + + bool MatchesContext(ExecutionContext &exe_ctx); + + //------------------------------------------------------------------ + /// Execute the parsed expression by callinng the derived class's + /// DoExecute method. + /// + /// @param[in] diagnostic_manager + /// A diagnostic manager to report errors to. + /// + /// @param[in] exe_ctx + /// The execution context to use when looking up entities that + /// are needed for parsing (locations of variables, etc.) + /// + /// @param[in] options + /// Expression evaluation options. + /// + /// @param[in] shared_ptr_to_me + /// This is a shared pointer to this UserExpression. This is + /// needed because Execute can push a thread plan that will hold onto + /// the UserExpression for an unbounded period of time. So you + /// need to give the thread plan a reference to this object that can + /// keep it alive. + /// + /// @param[in] result + /// A pointer to direct at the persistent variable in which the + /// expression's result is stored. + /// + /// @return + /// A Process::Execution results value. + //------------------------------------------------------------------ + lldb::ExpressionResults Execute(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result); + + //------------------------------------------------------------------ + /// Apply the side effects of the function to program state. + /// + /// @param[in] diagnostic_manager + /// A diagnostic manager to report errors to. + /// + /// @param[in] exe_ctx + /// The execution context to use when looking up entities that + /// are needed for parsing (locations of variables, etc.) + /// + /// @param[in] result + /// A pointer to direct at the persistent variable in which the + /// expression's result is stored. + /// + /// @param[in] function_stack_pointer + /// A pointer to the base of the function's stack frame. This + /// is used to determine whether the expression result resides in + /// memory that will still be valid, or whether it needs to be + /// treated as homeless for the purpose of future expressions. + /// + /// @return + /// A Process::Execution results value. + //------------------------------------------------------------------ + virtual bool FinalizeJITExecution( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) = 0; + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. + //------------------------------------------------------------------ + const char *Text() override { return m_expr_text.c_str(); } + + //------------------------------------------------------------------ + /// Return the string that the user typed. + //------------------------------------------------------------------ + const char *GetUserText() { return m_expr_text.c_str(); } + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + const char *FunctionName() override { return "$__lldb_expr"; } + + //------------------------------------------------------------------ + /// Return the language that should be used when parsing. To use + /// the default, return eLanguageTypeUnknown. + //------------------------------------------------------------------ + lldb::LanguageType Language() override { return m_language; } + + //------------------------------------------------------------------ + /// Return the desired result type of the function, or + /// eResultTypeAny if indifferent. + //------------------------------------------------------------------ + ResultType DesiredResultType() override { return m_desired_type; } + + //------------------------------------------------------------------ + /// Return true if validation code should be inserted into the + /// expression. + //------------------------------------------------------------------ + bool NeedsValidation() override { return true; } + + //------------------------------------------------------------------ + /// Return true if external variables in the expression should be + /// resolved. + //------------------------------------------------------------------ + bool NeedsVariableResolution() override { return true; } + + EvaluateExpressionOptions *GetOptions() override { return &m_options; } + + virtual lldb::ExpressionVariableSP + GetResultAfterDematerialization(ExecutionContextScope *exe_scope) { + return lldb::ExpressionVariableSP(); + } + + virtual lldb::ModuleSP GetJITModule() { return lldb::ModuleSP(); } + + //------------------------------------------------------------------ + /// Evaluate one expression in the scratch context of the + /// target passed in the exe_ctx and return its result. + /// + /// @param[in] exe_ctx + /// The execution context to use when evaluating the expression. + /// + /// @param[in] options + /// Expression evaluation options. N.B. The language in the + /// evaluation options will be used to determine the language used for + /// expression evaluation. + /// + /// @param[in] expr_cstr + /// A C string containing the expression to be evaluated. + /// + /// @param[in] expr_prefix + /// If non-nullptr, a C string containing translation-unit level + /// definitions to be included when the expression is parsed. + /// + /// @param[in,out] result_valobj_sp + /// If execution is successful, the result valobj is placed here. + /// + /// @param[out] error + /// Filled in with an error in case the expression evaluation + /// fails to parse, run, or evaluated. + /// + /// @param[in] line_offset + /// The offset of the first line of the expression from the "beginning" of + /// a virtual source file used for error reporting and debug info. + /// + /// @param[out] fixed_expression + /// If non-nullptr, the fixed expression is copied into the provided + /// string. + /// + /// @param[out] jit_module_sp_ptr + /// If non-nullptr, used to persist the generated IR module. + /// + /// @result + /// A Process::ExpressionResults value. eExpressionCompleted for + /// success. + //------------------------------------------------------------------ + static lldb::ExpressionResults + Evaluate(ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options, + llvm::StringRef expr_cstr, llvm::StringRef expr_prefix, + lldb::ValueObjectSP &result_valobj_sp, Status &error, + uint32_t line_offset = 0, std::string *fixed_expression = nullptr, + lldb::ModuleSP *jit_module_sp_ptr = nullptr); + + static const Status::ValueType kNoResult = + 0x1001; ///< ValueObject::GetError() returns this if there is no result + /// from the expression. + + const char *GetFixedText() { + if (m_fixed_text.empty()) + return nullptr; + return m_fixed_text.c_str(); + } + +protected: + virtual lldb::ExpressionResults + DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) = 0; + + static lldb::addr_t GetObjectPointer(lldb::StackFrameSP frame_sp, + ConstString &object_name, Status &err); + + //------------------------------------------------------------------ + /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the + /// environment. + //------------------------------------------------------------------ + + void InstallContext(ExecutionContext &exe_ctx); + + bool LockAndCheckContext(ExecutionContext &exe_ctx, lldb::TargetSP &target_sp, + lldb::ProcessSP &process_sp, + lldb::StackFrameSP &frame_sp); + + Address m_address; ///< The address the process is stopped in. + std::string m_expr_text; ///< The text of the expression, as typed by the user + std::string m_expr_prefix; ///< The text of the translation-level definitions, + ///as provided by the user + std::string m_fixed_text; ///< The text of the expression with fix-its applied + ///- this won't be set if the fixed text doesn't + ///parse. + lldb::LanguageType m_language; ///< The language to use when parsing + ///(eLanguageTypeUnknown means use defaults) + ResultType m_desired_type; ///< The type to coerce the expression's result to. + ///If eResultTypeAny, inferred from the expression. + EvaluateExpressionOptions + m_options; ///< Additional options provided by the user. +}; + +} // namespace lldb_private + +#endif // liblldb_UserExpression_h_ diff --git a/include/lldb/Expression/UtilityFunction.h b/include/lldb/Expression/UtilityFunction.h new file mode 100644 index 000000000..9c54db35f --- /dev/null +++ b/include/lldb/Expression/UtilityFunction.h @@ -0,0 +1,143 @@ +//===-- UtilityFunction.h ----------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UtilityFunction_h_ +#define liblldb_UtilityFunction_h_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Expression/Expression.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class UtilityFunction UtilityFunction.h "lldb/Expression/UtilityFunction.h" +/// @brief Encapsulates a bit of source code that provides a function that is +/// callable +/// +/// LLDB uses expressions for various purposes, notably to call functions +/// and as a backend for the expr command. UtilityFunction encapsulates +/// a self-contained function meant to be used from other code. Utility +/// functions can perform error-checking for ClangUserExpressions, +//---------------------------------------------------------------------- +class UtilityFunction : public Expression { +public: + //------------------------------------------------------------------ + /// Constructor + /// + /// @param[in] text + /// The text of the function. Must be a full translation unit. + /// + /// @param[in] name + /// The name of the function, as used in the text. + //------------------------------------------------------------------ + UtilityFunction(ExecutionContextScope &exe_scope, const char *text, + const char *name); + + ~UtilityFunction() override; + + //------------------------------------------------------------------ + /// Install the utility function into a process + /// + /// @param[in] diagnostic_manager + /// A diagnostic manager to print parse errors and warnings to. + /// + /// @param[in] exe_ctx + /// The execution context to install the utility function to. + /// + /// @return + /// True on success (no errors); false otherwise. + //------------------------------------------------------------------ + virtual bool Install(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx) = 0; + + //------------------------------------------------------------------ + /// Check whether the given PC is inside the function + /// + /// Especially useful if the function dereferences nullptr to indicate a + /// failed + /// assert. + /// + /// @param[in] pc + /// The program counter to check. + /// + /// @return + /// True if the program counter falls within the function's bounds; + /// false if not (or the function is not JIT compiled) + //------------------------------------------------------------------ + bool ContainsAddress(lldb::addr_t address) { + // nothing is both >= LLDB_INVALID_ADDRESS and < LLDB_INVALID_ADDRESS, + // so this always returns false if the function is not JIT compiled yet + return (address >= m_jit_start_addr && address < m_jit_end_addr); + } + + //------------------------------------------------------------------ + /// Return the string that the parser should parse. Must be a full + /// translation unit. + //------------------------------------------------------------------ + const char *Text() override { return m_function_text.c_str(); } + + //------------------------------------------------------------------ + /// Return the function name that should be used for executing the + /// expression. Text() should contain the definition of this + /// function. + //------------------------------------------------------------------ + const char *FunctionName() override { return m_function_name.c_str(); } + + //------------------------------------------------------------------ + /// Return the object that the parser should use when registering + /// local variables. May be nullptr if the Expression doesn't care. + //------------------------------------------------------------------ + ExpressionVariableList *LocalVariables() { return nullptr; } + + //------------------------------------------------------------------ + /// Return true if validation code should be inserted into the + /// expression. + //------------------------------------------------------------------ + bool NeedsValidation() override { return false; } + + //------------------------------------------------------------------ + /// Return true if external variables in the expression should be + /// resolved. + //------------------------------------------------------------------ + bool NeedsVariableResolution() override { return false; } + + // This makes the function caller function. + // Pass in the ThreadSP if you have one available, compilation can end up + // calling code (e.g. to look up indirect + // functions) and we don't want this to wander onto another thread. + FunctionCaller *MakeFunctionCaller(const CompilerType &return_type, + const ValueList &arg_value_list, + lldb::ThreadSP compilation_thread, + Status &error); + + // This one retrieves the function caller that is already made. If you + // haven't made it yet, this returns nullptr + FunctionCaller *GetFunctionCaller() { return m_caller_up.get(); } + +protected: + std::shared_ptr m_execution_unit_sp; + lldb::ModuleWP m_jit_module_wp; + std::string m_function_text; ///< The text of the function. Must be a + ///well-formed translation unit. + std::string m_function_name; ///< The name of the function. + std::unique_ptr m_caller_up; +}; + +} // namespace lldb_private + +#endif // liblldb_UtilityFunction_h_ diff --git a/include/lldb/Host/Config.h b/include/lldb/Host/Config.h new file mode 100644 index 000000000..3fa19e774 --- /dev/null +++ b/include/lldb/Host/Config.h @@ -0,0 +1,31 @@ +//===-- Config.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_CONFIG_H +#define LLDB_HOST_CONFIG_H + +#if defined(__APPLE__) + +// This block of code only exists to keep the Xcode project working in the +// absence of a configuration step. +#define LLDB_CONFIG_TERMIOS_SUPPORTED 1 + +#define HAVE_SYS_EVENT_H 1 + +#define HAVE_PPOLL 0 + +#define HAVE_SIGACTION 1 + +#else + +#error This file is only used by the Xcode build. + +#endif + +#endif // #ifndef LLDB_HOST_CONFIG_H diff --git a/include/lldb/Host/Config.h.cmake b/include/lldb/Host/Config.h.cmake new file mode 100644 index 000000000..0deedd151 --- /dev/null +++ b/include/lldb/Host/Config.h.cmake @@ -0,0 +1,27 @@ +//===-- Config.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_HOST_CONFIG_H +#define LLDB_HOST_CONFIG_H + +#cmakedefine LLDB_CONFIG_TERMIOS_SUPPORTED + +#cmakedefine LLDB_DISABLE_POSIX + +#cmakedefine01 HAVE_SYS_EVENT_H + +#cmakedefine01 HAVE_PPOLL + +#cmakedefine01 HAVE_SIGACTION + +#cmakedefine01 HAVE_PROCESS_VM_READV + +#cmakedefine01 HAVE_NR_PROCESS_VM_READV + +#endif // #ifndef LLDB_HOST_CONFIG_H diff --git a/include/lldb/Host/ConnectionFileDescriptor.h b/include/lldb/Host/ConnectionFileDescriptor.h new file mode 100644 index 000000000..0d486a34c --- /dev/null +++ b/include/lldb/Host/ConnectionFileDescriptor.h @@ -0,0 +1,15 @@ +//===-- 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_Host_ConnectionFileDescriptor_h_ +#define liblldb_Host_ConnectionFileDescriptor_h_ + +#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h" + +#endif diff --git a/include/lldb/Host/Debug.h b/include/lldb/Host/Debug.h new file mode 100644 index 000000000..fc190a4ec --- /dev/null +++ b/include/lldb/Host/Debug.h @@ -0,0 +1,160 @@ +//===-- Debug.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Debug_h_ +#define liblldb_Debug_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" + +namespace lldb_private { + +//------------------------------------------------------------------ +// Tells a thread what it needs to do when the process is resumed. +//------------------------------------------------------------------ +struct ResumeAction { + lldb::tid_t tid; // The thread ID that this action applies to, + // LLDB_INVALID_THREAD_ID for the default thread action + lldb::StateType state; // Valid values are eStateStopped/eStateSuspended, + // eStateRunning, and eStateStepping. + int signal; // When resuming this thread, resume it with this signal if this + // value is > 0 +}; + +//------------------------------------------------------------------ +// A class that contains instructions for all threads for +// NativeProcessProtocol::Resume(). Each thread can either run, stay +// suspended, or step when the process is resumed. We optionally +// have the ability to also send a signal to the thread when the +// action is run or step. +//------------------------------------------------------------------ +class ResumeActionList { +public: + ResumeActionList() : m_actions(), m_signal_handled() {} + + ResumeActionList(lldb::StateType default_action, int signal) + : m_actions(), m_signal_handled() { + SetDefaultThreadActionIfNeeded(default_action, signal); + } + + ResumeActionList(const ResumeAction *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); + } + } + + ~ResumeActionList() = default; + + bool IsEmpty() const { return m_actions.empty(); } + + void Append(const ResumeAction &action) { + m_actions.push_back(action); + m_signal_handled.push_back(false); + } + + void AppendAction(lldb::tid_t tid, lldb::StateType state, int signal = 0) { + ResumeAction action = {tid, state, signal}; + Append(action); + } + + void AppendResumeAll() { + AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateRunning); + } + + void AppendSuspendAll() { + AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateStopped); + } + + void AppendStepAll() { + AppendAction(LLDB_INVALID_THREAD_ID, lldb::eStateStepping); + } + + const ResumeAction *GetActionForThread(lldb::tid_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 != LLDB_INVALID_THREAD_ID) + return GetActionForThread(LLDB_INVALID_THREAD_ID, false); + return nullptr; + } + + size_t NumActionsWithState(lldb::StateType 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 SetDefaultThreadActionIfNeeded(lldb::StateType action, int signal) { + if (GetActionForThread(LLDB_INVALID_THREAD_ID, true) == nullptr) { + // There isn't a default action so we do need to set it. + ResumeAction default_action = {LLDB_INVALID_THREAD_ID, action, signal}; + 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 SetSignalHandledForThread(lldb::tid_t tid) const { + if (tid != LLDB_INVALID_THREAD_ID) { + 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; + } + } + } + + const ResumeAction *GetFirst() const { return m_actions.data(); } + + size_t GetSize() const { return m_actions.size(); } + + void Clear() { + m_actions.clear(); + m_signal_handled.clear(); + } + +protected: + std::vector m_actions; + mutable std::vector m_signal_handled; +}; + +struct ThreadStopInfo { + lldb::StopReason reason; + union { + // eStopReasonSignal + struct { + uint32_t signo; + } signal; + + // eStopReasonException + struct { + uint64_t type; + uint32_t data_count; + lldb::addr_t data[8]; + } exception; + } details; +}; +} + +#endif // liblldb_Debug_h_ diff --git a/include/lldb/Host/Editline.h b/include/lldb/Host/Editline.h new file mode 100644 index 000000000..0b75e9c92 --- /dev/null +++ b/include/lldb/Host/Editline.h @@ -0,0 +1,374 @@ +//===-- Editline.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// TODO: wire up window size changes + +// If we ever get a private copy of libedit, there are a number of defects that +// would be nice to fix; +// a) Sometimes text just disappears while editing. In an 80-column editor +// paste the following text, without +// the quotes: +// "This is a test of the input system missing Hello, World! Do you +// disappear when it gets to a particular length?" +// Now press ^A to move to the start and type 3 characters, and you'll see a +// good amount of the text will +// disappear. It's still in the buffer, just invisible. +// b) The prompt printing logic for dealing with ANSI formatting characters is +// broken, which is why we're +// working around it here. +// c) When resizing the terminal window, if the cursor moves between rows +// libedit will get confused. +// d) The incremental search uses escape to cancel input, so it's confused by +// ANSI sequences starting with escape. +// e) Emoji support is fairly terrible, presumably it doesn't understand +// composed characters? + +#ifndef liblldb_Editline_h_ +#define liblldb_Editline_h_ +#if defined(__cplusplus) + +#include +#include +#include + +// components needed to handle wide characters ( , codecvt_utf8, +// libedit built with '--enable-widec' ) +// are available on some platforms. The wchar_t versions of libedit functions +// will only be +// used in cases where this is true. This is a compile time dependecy, for now +// selected per target Platform +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ + defined(__OpenBSD__) +#define LLDB_EDITLINE_USE_WCHAR 1 +#include +#else +#define LLDB_EDITLINE_USE_WCHAR 0 +#endif + +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/lldb-private.h" + +#if defined(_WIN32) +#include "lldb/Host/windows/editlinewin.h" +#elif !defined(__ANDROID__) +#include +#endif + +#include +#include +#include + +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { +namespace line_editor { + +// type alias's to help manage 8 bit and wide character versions of libedit +#if LLDB_EDITLINE_USE_WCHAR +using EditLineStringType = std::wstring; +using EditLineStringStreamType = std::wstringstream; +using EditLineCharType = wchar_t; +#else +using EditLineStringType = std::string; +using EditLineStringStreamType = std::stringstream; +using EditLineCharType = char; +#endif + +#ifdef EL_CLIENTDATA /* editline with wide support + wide char read function */ +using EditLineGetCharType = wchar_t; +#else +using EditLineGetCharType = char; +#endif + +typedef int (*EditlineGetCharCallbackType)(::EditLine *editline, + EditLineGetCharType *c); +typedef unsigned char (*EditlineCommandCallbackType)(::EditLine *editline, + int ch); +typedef const char *(*EditlinePromptCallbackType)(::EditLine *editline); + +class EditlineHistory; + +typedef std::shared_ptr EditlineHistorySP; + +typedef bool (*IsInputCompleteCallbackType)(Editline *editline, + StringList &lines, void *baton); + +typedef int (*FixIndentationCallbackType)(Editline *editline, + const StringList &lines, + int cursor_position, void *baton); + +typedef int (*CompleteCallbackType)(const char *current_line, + const char *cursor, const char *last_char, + int skip_first_n_matches, int max_matches, + StringList &matches, void *baton); + +/// Status used to decide when and how to start editing another line in +/// multi-line sessions +enum class EditorStatus { + + /// The default state proceeds to edit the current line + Editing, + + /// Editing complete, returns the complete set of edited lines + Complete, + + /// End of input reported + EndOfInput, + + /// Editing interrupted + Interrupted +}; + +/// Established locations that can be easily moved among with MoveCursor +enum class CursorLocation { + /// The start of the first line in a multi-line edit session + BlockStart, + + /// The start of the current line in a multi-line edit session + EditingPrompt, + + /// The location of the cursor on the current line in a multi-line edit + /// session + EditingCursor, + + /// The location immediately after the last character in a multi-line edit + /// session + BlockEnd +}; +} + +using namespace line_editor; + +/// Instances of Editline provide an abstraction over libedit's EditLine +/// facility. Both +/// single- and multi-line editing are supported. +class Editline { +public: + Editline(const char *editor_name, FILE *input_file, FILE *output_file, + FILE *error_file, bool color_prompts); + + ~Editline(); + + /// Uses the user data storage of EditLine to retrieve an associated instance + /// of Editline. + static Editline *InstanceFor(::EditLine *editline); + + /// Sets a string to be used as a prompt, or combined with a line number to + /// form a prompt. + void SetPrompt(const char *prompt); + + /// Sets an alternate string to be used as a prompt for the second line and + /// beyond in multi-line + /// editing scenarios. + void SetContinuationPrompt(const char *continuation_prompt); + + /// Required to update the width of the terminal registered for I/O. It is + /// critical that this + /// be correct at all times. + void TerminalSizeChanged(); + + /// Returns the prompt established by SetPrompt() + const char *GetPrompt(); + + /// Returns the index of the line currently being edited + uint32_t GetCurrentLine(); + + /// Interrupt the current edit as if ^C was pressed + bool Interrupt(); + + /// Cancel this edit and oblitarate all trace of it + bool Cancel(); + + /// Register a callback for the tab key + void SetAutoCompleteCallback(CompleteCallbackType callback, void *baton); + + /// Register a callback for testing whether multi-line input is complete + void SetIsInputCompleteCallback(IsInputCompleteCallbackType callback, + void *baton); + + /// Register a callback for determining the appropriate indentation for a line + /// when creating a newline. An optional set of insertable characters can + /// also + /// trigger the callback. + bool SetFixIndentationCallback(FixIndentationCallbackType callback, + void *baton, const char *indent_chars); + + /// Prompts for and reads a single line of user input. + bool GetLine(std::string &line, bool &interrupted); + + /// Prompts for and reads a multi-line batch of user input. + bool GetLines(int first_line_number, StringList &lines, bool &interrupted); + + void PrintAsync(Stream *stream, const char *s, size_t len); + +private: + /// Sets the lowest line number for multi-line editing sessions. A value of + /// zero suppresses + /// line number printing in the prompt. + void SetBaseLineNumber(int line_number); + + /// Returns the complete prompt by combining the prompt or continuation prompt + /// with line numbers + /// as appropriate. The line index is a zero-based index into the current + /// multi-line session. + std::string PromptForIndex(int line_index); + + /// Sets the current line index between line edits to allow free movement + /// between lines. Updates + /// the prompt to match. + void SetCurrentLine(int line_index); + + /// Determines the width of the prompt in characters. The width is guaranteed + /// to be the same for + /// all lines of the current multi-line session. + int GetPromptWidth(); + + /// Returns true if the underlying EditLine session's keybindings are + /// Emacs-based, or false if + /// they are VI-based. + bool IsEmacs(); + + /// Returns true if the current EditLine buffer contains nothing but spaces, + /// or is empty. + bool IsOnlySpaces(); + + /// Helper method used by MoveCursor to determine relative line position. + int GetLineIndexForLocation(CursorLocation location, int cursor_row); + + /// Move the cursor from one well-established location to another using + /// relative line positioning + /// and absolute column positioning. + void MoveCursor(CursorLocation from, CursorLocation to); + + /// Clear from cursor position to bottom of screen and print input lines + /// including prompts, optionally + /// starting from a specific line. Lines are drawn with an extra space at the + /// end to reserve room for + /// the rightmost cursor position. + void DisplayInput(int firstIndex = 0); + + /// Counts the number of rows a given line of content will end up occupying, + /// taking into account both + /// the preceding prompt and a single trailing space occupied by a cursor when + /// at the end of the line. + int CountRowsForLine(const EditLineStringType &content); + + /// Save the line currently being edited + void SaveEditedLine(); + + /// Convert the current input lines into a UTF8 StringList + StringList GetInputAsStringList(int line_count = UINT32_MAX); + + /// Replaces the current multi-line session with the next entry from history. + /// When the parameter is + /// true it will take the next earlier entry from history, when it is false it + /// takes the next most + /// recent. + unsigned char RecallHistory(bool earlier); + + /// Character reading implementation for EditLine that supports our multi-line + /// editing trickery. + int GetCharacter(EditLineGetCharType *c); + + /// Prompt implementation for EditLine. + const char *Prompt(); + + /// Line break command used when meta+return is pressed in multi-line mode. + unsigned char BreakLineCommand(int ch); + + /// Command used when return is pressed in multi-line mode. + unsigned char EndOrAddLineCommand(int ch); + + /// Delete command used when delete is pressed in multi-line mode. + unsigned char DeleteNextCharCommand(int ch); + + /// Delete command used when backspace is pressed in multi-line mode. + unsigned char DeletePreviousCharCommand(int ch); + + /// Line navigation command used when ^P or up arrow are pressed in multi-line + /// mode. + unsigned char PreviousLineCommand(int ch); + + /// Line navigation command used when ^N or down arrow are pressed in + /// multi-line mode. + unsigned char NextLineCommand(int ch); + + /// History navigation command used when Alt + up arrow is pressed in + /// multi-line mode. + unsigned char PreviousHistoryCommand(int ch); + + /// History navigation command used when Alt + down arrow is pressed in + /// multi-line mode. + unsigned char NextHistoryCommand(int ch); + + /// Buffer start command used when Esc < is typed in multi-line emacs mode. + unsigned char BufferStartCommand(int ch); + + /// Buffer end command used when Esc > is typed in multi-line emacs mode. + unsigned char BufferEndCommand(int ch); + + /// Context-sensitive tab insertion or code completion command used when the + /// tab key is typed. + unsigned char TabCommand(int ch); + + /// Respond to normal character insertion by fixing line indentation + unsigned char FixIndentationCommand(int ch); + + /// Revert line command used when moving between lines. + unsigned char RevertLineCommand(int ch); + + /// Ensures that the current EditLine instance is properly configured for + /// single or multi-line editing. + void ConfigureEditor(bool multiline); + + bool CompleteCharacter(char ch, EditLineGetCharType &out); + +private: +#if LLDB_EDITLINE_USE_WCHAR + std::wstring_convert> m_utf8conv; +#endif + ::EditLine *m_editline = nullptr; + EditlineHistorySP m_history_sp; + bool m_in_history = false; + std::vector m_live_history_lines; + bool m_multiline_enabled = false; + std::vector m_input_lines; + EditorStatus m_editor_status; + bool m_color_prompts = true; + int m_terminal_width = 0; + int m_base_line_number = 0; + unsigned m_current_line_index = 0; + int m_current_line_rows = -1; + int m_revert_cursor_index = 0; + int m_line_number_digits = 3; + std::string m_set_prompt; + std::string m_set_continuation_prompt; + std::string m_current_prompt; + bool m_needs_prompt_repaint = false; + std::string m_editor_name; + FILE *m_input_file; + FILE *m_output_file; + FILE *m_error_file; + ConnectionFileDescriptor m_input_connection; + IsInputCompleteCallbackType m_is_input_complete_callback = nullptr; + void *m_is_input_complete_callback_baton = nullptr; + FixIndentationCallbackType m_fix_indentation_callback = nullptr; + void *m_fix_indentation_callback_baton = nullptr; + const char *m_fix_indentation_callback_chars = nullptr; + CompleteCallbackType m_completion_callback = nullptr; + void *m_completion_callback_baton = nullptr; + + std::mutex m_output_mutex; +}; +} + +#endif // #if defined(__cplusplus) +#endif // liblldb_Editline_h_ diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h new file mode 100644 index 000000000..1dfa12ea5 --- /dev/null +++ b/include/lldb/Host/File.h @@ -0,0 +1,489 @@ +//===-- File.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_File_h_ +#define liblldb_File_h_ + +#include "lldb/Host/PosixApi.h" +#include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-private.h" + +#include +#include +#include + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class File File.h "lldb/Host/File.h" +/// @brief A file class. +/// +/// A file class that divides abstracts the LLDB core from host file +/// functionality. +//---------------------------------------------------------------------- +class File : public IOObject { +public: + static int kInvalidDescriptor; + static FILE *kInvalidStream; + + enum OpenOptions { + eOpenOptionRead = (1u << 0), // Open file for reading + eOpenOptionWrite = (1u << 1), // Open file for writing + eOpenOptionAppend = + (1u << 2), // Don't truncate file when opening, append to end of file + eOpenOptionTruncate = (1u << 3), // Truncate file when opening + eOpenOptionNonBlocking = (1u << 4), // File reads + eOpenOptionCanCreate = (1u << 5), // Create file if doesn't already exist + eOpenOptionCanCreateNewOnly = + (1u << 6), // Can create file only if it doesn't already exist + eOpenOptionDontFollowSymlinks = (1u << 7), + eOpenOptionCloseOnExec = + (1u << 8) // Close the file when executing a new process + }; + + static mode_t ConvertOpenOptionsForPOSIXOpen(uint32_t open_options); + + File() + : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor), + m_stream(kInvalidStream), m_options(0), m_own_stream(false), + m_is_interactive(eLazyBoolCalculate), + m_is_real_terminal(eLazyBoolCalculate) {} + + File(FILE *fh, bool transfer_ownership) + : IOObject(eFDTypeFile, false), m_descriptor(kInvalidDescriptor), + m_stream(fh), m_options(0), m_own_stream(transfer_ownership), + m_is_interactive(eLazyBoolCalculate), + m_is_real_terminal(eLazyBoolCalculate) {} + + //------------------------------------------------------------------ + /// Constructor with path. + /// + /// Takes a path to a file which can be just a filename, or a full + /// path. If \a path is not nullptr or empty, this function will call + /// File::Open (const char *path, uint32_t options, uint32_t permissions). + /// + /// @param[in] path + /// The full or partial path to a file. + /// + /// @param[in] options + /// Options to use when opening (see File::OpenOptions) + /// + /// @param[in] permissions + /// Options to use when opening (see File::Permissions) + /// + /// @see File::Open (const char *path, uint32_t options, uint32_t permissions) + //------------------------------------------------------------------ + File(const char *path, uint32_t options, + uint32_t permissions = lldb::eFilePermissionsFileDefault); + + //------------------------------------------------------------------ + /// Constructor with FileSpec. + /// + /// Takes a FileSpec pointing to a file which can be just a filename, or a + /// full + /// path. If \a path is not nullptr or empty, this function will call + /// File::Open (const char *path, uint32_t options, uint32_t permissions). + /// + /// @param[in] filespec + /// The FileSpec for this file. + /// + /// @param[in] options + /// Options to use when opening (see File::OpenOptions) + /// + /// @param[in] permissions + /// Options to use when opening (see File::Permissions) + /// + /// @see File::Open (const char *path, uint32_t options, uint32_t permissions) + //------------------------------------------------------------------ + File(const FileSpec &filespec, uint32_t options, + uint32_t permissions = lldb::eFilePermissionsFileDefault); + + File(int fd, bool transfer_ownership) + : IOObject(eFDTypeFile, transfer_ownership), m_descriptor(fd), + m_stream(kInvalidStream), m_options(0), m_own_stream(false), + m_is_interactive(eLazyBoolCalculate), + m_is_real_terminal(eLazyBoolCalculate) {} + + //------------------------------------------------------------------ + /// Destructor. + /// + /// The destructor is virtual in case this class is subclassed. + //------------------------------------------------------------------ + ~File() override; + + bool IsValid() const override { + return DescriptorIsValid() || StreamIsValid(); + } + + //------------------------------------------------------------------ + /// Convert to pointer operator. + /// + /// This allows code to check a File object to see if it + /// contains anything valid using code such as: + /// + /// @code + /// File file(...); + /// if (file) + /// { ... + /// @endcode + /// + /// @return + /// A pointer to this object if either the directory or filename + /// is valid, nullptr otherwise. + //------------------------------------------------------------------ + operator bool() const { return DescriptorIsValid() || StreamIsValid(); } + + //------------------------------------------------------------------ + /// Logical NOT operator. + /// + /// This allows code to check a File object to see if it is + /// invalid using code such as: + /// + /// @code + /// File file(...); + /// if (!file) + /// { ... + /// @endcode + /// + /// @return + /// Returns \b true if the object has an empty directory and + /// filename, \b false otherwise. + //------------------------------------------------------------------ + bool operator!() const { return !DescriptorIsValid() && !StreamIsValid(); } + + //------------------------------------------------------------------ + /// Get the file spec for this file. + /// + /// @return + /// A reference to the file specification object. + //------------------------------------------------------------------ + Status GetFileSpec(FileSpec &file_spec) const; + + //------------------------------------------------------------------ + /// Open a file for read/writing with the specified options. + /// + /// Takes a path to a file which can be just a filename, or a full + /// path. + /// + /// @param[in] path + /// The full or partial path to a file. + /// + /// @param[in] options + /// Options to use when opening (see File::OpenOptions) + /// + /// @param[in] permissions + /// Options to use when opening (see File::Permissions) + //------------------------------------------------------------------ + Status Open(const char *path, uint32_t options, + uint32_t permissions = lldb::eFilePermissionsFileDefault); + + Status Close() override; + + void Clear(); + + int GetDescriptor() const; + + WaitableHandle GetWaitableHandle() override; + + void SetDescriptor(int fd, bool transfer_ownership); + + FILE *GetStream(); + + void SetStream(FILE *fh, bool transfer_ownership); + + //------------------------------------------------------------------ + /// Read bytes from a file from the current file position. + /// + /// NOTE: This function is NOT thread safe. Use the read function + /// that takes an "off_t &offset" to ensure correct operation in + /// multi-threaded environments. + /// + /// @param[in] buf + /// A buffer where to put the bytes that are read. + /// + /// @param[in,out] num_bytes + /// The number of bytes to read form the current file position + /// which gets modified with the number of bytes that were read. + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Read(void *buf, size_t &num_bytes) override; + + //------------------------------------------------------------------ + /// Write bytes to a file at the current file position. + /// + /// NOTE: This function is NOT thread safe. Use the write function + /// that takes an "off_t &offset" to ensure correct operation in + /// multi-threaded environments. + /// + /// @param[in] buf + /// A buffer where to put the bytes that are read. + /// + /// @param[in,out] num_bytes + /// The number of bytes to write to the current file position + /// which gets modified with the number of bytes that were + /// written. + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Write(const void *buf, size_t &num_bytes) override; + + //------------------------------------------------------------------ + /// Seek to an offset relative to the beginning of the file. + /// + /// NOTE: This function is NOT thread safe, other threads that + /// access this object might also change the current file position. + /// For thread safe reads and writes see the following functions: + /// @see File::Read (void *, size_t, off_t &) + /// @see File::Write (const void *, size_t, off_t &) + /// + /// @param[in] offset + /// The offset to seek to within the file relative to the + /// beginning of the file. + /// + /// @param[in] error_ptr + /// A pointer to a lldb_private::Status object that will be + /// filled in if non-nullptr. + /// + /// @return + /// The resulting seek offset, or -1 on error. + //------------------------------------------------------------------ + off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr); + + //------------------------------------------------------------------ + /// Seek to an offset relative to the current file position. + /// + /// NOTE: This function is NOT thread safe, other threads that + /// access this object might also change the current file position. + /// For thread safe reads and writes see the following functions: + /// @see File::Read (void *, size_t, off_t &) + /// @see File::Write (const void *, size_t, off_t &) + /// + /// @param[in] offset + /// The offset to seek to within the file relative to the + /// current file position. + /// + /// @param[in] error_ptr + /// A pointer to a lldb_private::Status object that will be + /// filled in if non-nullptr. + /// + /// @return + /// The resulting seek offset, or -1 on error. + //------------------------------------------------------------------ + off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr); + + //------------------------------------------------------------------ + /// Seek to an offset relative to the end of the file. + /// + /// NOTE: This function is NOT thread safe, other threads that + /// access this object might also change the current file position. + /// For thread safe reads and writes see the following functions: + /// @see File::Read (void *, size_t, off_t &) + /// @see File::Write (const void *, size_t, off_t &) + /// + /// @param[in,out] offset + /// The offset to seek to within the file relative to the + /// end of the file which gets filled in with the resulting + /// absolute file offset. + /// + /// @param[in] error_ptr + /// A pointer to a lldb_private::Status object that will be + /// filled in if non-nullptr. + /// + /// @return + /// The resulting seek offset, or -1 on error. + //------------------------------------------------------------------ + off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr); + + //------------------------------------------------------------------ + /// Read bytes from a file from the specified file offset. + /// + /// NOTE: This function is thread safe in that clients manager their + /// own file position markers and reads on other threads won't mess + /// up the current read. + /// + /// @param[in] dst + /// A buffer where to put the bytes that are read. + /// + /// @param[in,out] num_bytes + /// The number of bytes to read form the current file position + /// which gets modified with the number of bytes that were read. + /// + /// @param[in,out] offset + /// The offset within the file from which to read \a num_bytes + /// bytes. This offset gets incremented by the number of bytes + /// that were read. + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Read(void *dst, size_t &num_bytes, off_t &offset); + + //------------------------------------------------------------------ + /// Read bytes from a file from the specified file offset. + /// + /// NOTE: This function is thread safe in that clients manager their + /// own file position markers and reads on other threads won't mess + /// up the current read. + /// + /// @param[in,out] num_bytes + /// The number of bytes to read form the current file position + /// which gets modified with the number of bytes that were read. + /// + /// @param[in,out] offset + /// The offset within the file from which to read \a num_bytes + /// bytes. This offset gets incremented by the number of bytes + /// that were read. + /// + /// @param[in] null_terminate + /// Ensure that the data that is read is terminated with a NULL + /// character so that the data can be used as a C string. + /// + /// @param[out] data_buffer_sp + /// A data buffer to create and fill in that will contain any + /// data that is read from the file. This buffer will be reset + /// if an error occurs. + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Read(size_t &num_bytes, off_t &offset, bool null_terminate, + lldb::DataBufferSP &data_buffer_sp); + + //------------------------------------------------------------------ + /// Write bytes to a file at the specified file offset. + /// + /// NOTE: This function is thread safe in that clients manager their + /// own file position markers, though clients will need to implement + /// their own locking externally to avoid multiple people writing + /// to the file at the same time. + /// + /// @param[in] src + /// A buffer containing the bytes to write. + /// + /// @param[in,out] num_bytes + /// The number of bytes to write to the file at offset \a offset. + /// \a num_bytes gets modified with the number of bytes that + /// were read. + /// + /// @param[in,out] offset + /// The offset within the file at which to write \a num_bytes + /// bytes. This offset gets incremented by the number of bytes + /// that were written. + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Write(const void *src, size_t &num_bytes, off_t &offset); + + //------------------------------------------------------------------ + /// Flush the current stream + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Flush(); + + //------------------------------------------------------------------ + /// Sync to disk. + /// + /// @return + /// An error object that indicates success or the reason for + /// failure. + //------------------------------------------------------------------ + Status Sync(); + + //------------------------------------------------------------------ + /// Get the permissions for a this file. + /// + /// @return + /// Bits logical OR'ed together from the permission bits defined + /// in lldb_private::File::Permissions. + //------------------------------------------------------------------ + uint32_t GetPermissions(Status &error) const; + + static uint32_t GetPermissions(const FileSpec &file_spec, Status &error); + + //------------------------------------------------------------------ + /// Return true if this file is interactive. + /// + /// @return + /// True if this file is a terminal (tty or pty), false + /// otherwise. + //------------------------------------------------------------------ + bool GetIsInteractive(); + + //------------------------------------------------------------------ + /// Return true if this file from a real terminal. + /// + /// Just knowing a file is a interactive isn't enough, we also need + /// to know if the terminal has a width and height so we can do + /// cursor movement and other terminal manipulations by sending + /// escape sequences. + /// + /// @return + /// True if this file is a terminal (tty, not a pty) that has + /// a non-zero width and height, false otherwise. + //------------------------------------------------------------------ + bool GetIsRealTerminal(); + + bool GetIsTerminalWithColors(); + + //------------------------------------------------------------------ + /// Output printf formatted output to the stream. + /// + /// Print some formatted output to the stream. + /// + /// @param[in] format + /// A printf style format string. + /// + /// @param[in] ... + /// Variable arguments that are needed for the printf style + /// format string \a format. + //------------------------------------------------------------------ + size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3))); + + size_t PrintfVarArg(const char *format, va_list args); + + void SetOptions(uint32_t options) { m_options = options; } + +protected: + bool DescriptorIsValid() const { return m_descriptor >= 0; } + + bool StreamIsValid() const { return m_stream != kInvalidStream; } + + void CalculateInteractiveAndTerminal(); + + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + int m_descriptor; + FILE *m_stream; + uint32_t m_options; + bool m_own_stream; + LazyBool m_is_interactive; + LazyBool m_is_real_terminal; + LazyBool m_supports_colors; + +private: + DISALLOW_COPY_AND_ASSIGN(File); +}; + +} // namespace lldb_private + +#endif // liblldb_File_h_ diff --git a/include/lldb/Host/FileCache.h b/include/lldb/Host/FileCache.h new file mode 100644 index 000000000..1c03540c1 --- /dev/null +++ b/include/lldb/Host/FileCache.h @@ -0,0 +1,47 @@ +//===-- FileCache.h ---------------------------------------------*- 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_FileCache_h +#define liblldb_Host_FileCache_h + +#include +#include + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" + +namespace lldb_private { +class FileCache { +private: + FileCache() {} + + typedef std::map FDToFileMap; + +public: + static FileCache &GetInstance(); + + lldb::user_id_t OpenFile(const FileSpec &file_spec, uint32_t flags, + uint32_t mode, Status &error); + bool CloseFile(lldb::user_id_t fd, Status &error); + + uint64_t WriteFile(lldb::user_id_t fd, uint64_t offset, const void *src, + uint64_t src_len, Status &error); + uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, + uint64_t dst_len, Status &error); + +private: + static FileCache *m_instance; + + FDToFileMap m_cache; +}; +} + +#endif diff --git a/include/lldb/Host/FileSystem.h b/include/lldb/Host/FileSystem.h new file mode 100644 index 000000000..c13d5c84c --- /dev/null +++ b/include/lldb/Host/FileSystem.h @@ -0,0 +1,42 @@ +//===-- FileSystem.h --------------------------------------------*- 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_FileSystem_h +#define liblldb_Host_FileSystem_h + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" +#include "llvm/Support/Chrono.h" + +#include "lldb/lldb-types.h" + +#include +#include +#include + +namespace lldb_private { +class FileSystem { +public: + static const char *DEV_NULL; + static const char *PATH_CONVERSION_ERROR; + + static Status Symlink(const FileSpec &src, const FileSpec &dst); + static Status Readlink(const FileSpec &src, FileSpec &dst); + + static Status ResolveSymbolicLink(const FileSpec &src, FileSpec &dst); + + /// Wraps ::fopen in a platform-independent way. Once opened, FILEs can be + /// manipulated and closed with the normal ::fread, ::fclose, etc. functions. + static FILE *Fopen(const char *path, const char *mode); + + static llvm::sys::TimePoint<> GetModificationTime(const FileSpec &file_spec); +}; +} + +#endif diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h new file mode 100644 index 000000000..da0b8e14c --- /dev/null +++ b/include/lldb/Host/Host.h @@ -0,0 +1,256 @@ +//===-- 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 LLDB_HOST_HOST_H +#define LLDB_HOST_HOST_H + +#include "lldb/Host/File.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/StringList.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-private.h" +#include +#include +#include +#include +#include + +namespace lldb_private { + +class FileAction; +class ProcessLaunchInfo; + +//---------------------------------------------------------------------- +// Exit Type for inferior processes +//---------------------------------------------------------------------- +struct WaitStatus { + enum Type : uint8_t { + Exit, // The status represents the return code from normal + // program exit (i.e. WIFEXITED() was true) + Signal, // The status represents the signal number that caused + // the program to exit (i.e. WIFSIGNALED() was true) + Stop, // The status represents the signal number that caused the + // program to stop (i.e. WIFSTOPPED() was true) + }; + + Type type; + uint8_t status; + + WaitStatus(Type type, uint8_t status) : type(type), status(status) {} + + static WaitStatus Decode(int wstatus); +}; + +//---------------------------------------------------------------------- +/// @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 std::function // Exit value of process if signal is zero + MonitorChildProcessCallback; + + //------------------------------------------------------------------ + /// 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 + /// monitoring 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 + /// regardless 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] pid + /// The process ID of a child process to monitor, -1 for all + /// processes. + /// + /// @param[in] monitor_signals + /// If \b true the callback will get called when the child + /// process gets a signal. If \b false, the callback will only + /// get called if the child process exits. + /// + /// @return + /// A thread handle that can be used to cancel the thread that + /// was spawned to monitor \a pid. + /// + /// @see static void Host::StopMonitoringChildProcess (uint32_t) + //------------------------------------------------------------------ + static HostThread + StartMonitoringChildProcess(const MonitorChildProcessCallback &callback, + lldb::pid_t pid, bool monitor_signals); + + enum SystemLogType { eSystemLogWarning, eSystemLogError }; + + static void SystemLog(SystemLogType type, const char *format, ...) + __attribute__((format(printf, 2, 3))); + + static void SystemLog(SystemLogType type, const char *format, va_list args); + + //------------------------------------------------------------------ + /// Get the process ID for the calling process. + /// + /// @return + /// The process ID for the current process. + //------------------------------------------------------------------ + static lldb::pid_t GetCurrentProcessID(); + + static void Kill(lldb::pid_t pid, int signo); + + //------------------------------------------------------------------ + /// Get the thread token (the one returned by ThreadCreate when the thread was + /// created) for the + /// calling thread in the current process. + /// + /// @return + /// The thread token for the calling thread in the current process. + //------------------------------------------------------------------ + static lldb::thread_t GetCurrentThread(); + + static const char *GetSignalAsCString(int signo); + + //------------------------------------------------------------------ + /// Given an address in the current process (the process that + /// is running the LLDB code), return the name of the module that + /// it comes from. This can be useful when you need to know the + /// path to the shared library that your code is running in for + /// loading resources that are relative to your binary. + /// + /// @param[in] host_addr + /// The pointer to some code in the current process. + /// + /// @return + /// \b A file spec with the module that contains \a host_addr, + /// which may be invalid if \a host_addr doesn't fall into + /// any valid module address range. + //------------------------------------------------------------------ + static FileSpec GetModuleFileSpecForHostAddress(const void *host_addr); + + //------------------------------------------------------------------ + /// If you have an executable that is in a bundle and want to get + /// back to the bundle directory from the path itself, this + /// function will change a path to a file within a bundle to the + /// bundle directory itself. + /// + /// @param[in] file + /// A file spec that might point to a file in a bundle. + /// + /// @param[out] bundle_directory + /// An object will be filled in with the bundle directory for + /// the bundle when \b true is returned. Otherwise \a file is + /// left untouched and \b false is returned. + /// + /// @return + /// \b true if \a file was resolved in \a bundle_directory, + /// \b false otherwise. + //------------------------------------------------------------------ + static bool GetBundleDirectory(const FileSpec &file, + FileSpec &bundle_directory); + + //------------------------------------------------------------------ + /// When executable files may live within a directory, where the + /// directory represents an executable bundle (like the MacOSX + /// app bundles), then locate the executable within the containing + /// bundle. + /// + /// @param[in,out] file + /// A file spec that currently points to the bundle that will + /// be filled in with the executable path within the bundle + /// if \b true is returned. Otherwise \a file is left untouched. + /// + /// @return + /// \b true if \a file was resolved, \b false if this function + /// was not able to resolve the path. + //------------------------------------------------------------------ + static bool ResolveExecutableInBundle(FileSpec &file); + + static uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos); + + typedef std::map TidMap; + typedef std::pair TidPair; + static bool FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach); + + static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info); + + static const lldb::UnixSignalsSP &GetUnixSignals(); + + static Status LaunchProcess(ProcessLaunchInfo &launch_info); + + //------------------------------------------------------------------ + /// Perform expansion of the command-line for this launch info + /// This can potentially involve wildcard expansion + // environment variable replacement, and whatever other + // argument magic the platform defines as part of its typical + // user experience + //------------------------------------------------------------------ + static Status ShellExpandArguments(ProcessLaunchInfo &launch_info); + + // TODO: Convert this function to take a StringRef. + static Status RunShellCommand( + const char *command, // Shouldn't be NULL + const FileSpec &working_dir, // Pass empty FileSpec to use the current + // working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the + // process to exit + std::string + *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec, + bool run_in_default_shell = true); + + static Status RunShellCommand( + const Args &args, + const FileSpec &working_dir, // Pass empty FileSpec to use the current + // working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the + // process to exit + std::string + *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec, + bool run_in_default_shell = true); + + static bool OpenFileInExternalEditor(const FileSpec &file_spec, + uint32_t line_no); + + static size_t GetEnvironment(StringList &env); + + static std::unique_ptr + CreateDefaultConnection(llvm::StringRef url); +}; + +} // namespace lldb_private + +namespace llvm { +template <> struct format_provider { + /// Options = "" gives a human readable description of the status + /// Options = "g" gives a gdb-remote protocol status (e.g., X09) + static void format(const lldb_private::WaitStatus &WS, raw_ostream &OS, + llvm::StringRef Options); +}; +} // namespace llvm + +#endif // LLDB_HOST_HOST_H diff --git a/include/lldb/Host/HostGetOpt.h b/include/lldb/Host/HostGetOpt.h new file mode 100644 index 000000000..d37a2526f --- /dev/null +++ b/include/lldb/Host/HostGetOpt.h @@ -0,0 +1,24 @@ +//===-- GetOpt.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#if !defined(_MSC_VER) && !defined(__NetBSD__) + +#ifdef _WIN32 +#define _BSD_SOURCE // Required so that getopt.h defines optreset +#endif + +#include +#include + +#else + +#include + +#endif diff --git a/include/lldb/Host/HostInfo.h b/include/lldb/Host/HostInfo.h new file mode 100644 index 000000000..b4a2f8baf --- /dev/null +++ b/include/lldb/Host/HostInfo.h @@ -0,0 +1,71 @@ +//===-- HostInfoBase.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_Host_HostInfo_h_ +#define lldb_Host_HostInfo_h_ + +//---------------------------------------------------------------------- +/// @class HostInfo HostInfo.h "lldb/Host/HostInfo.h" +/// @brief A class that provides host computer information. +/// +/// HostInfo is a class that answers information about the host operating +/// system. Note that HostInfo is NOT intended to be used to manipulate or +/// control the operating system. +/// +/// HostInfo is implemented in an OS-specific class (for example +/// HostInfoWindows) in a separate file, and then typedefed to HostInfo here. +/// Users of the class reference it as HostInfo::method(). +/// +/// Not all hosts provide the same functionality. It is important that methods +/// only be implemented at the lowest level at which they make sense. It should +/// be up to the clients of the class to ensure that they not attempt to call a +/// method which doesn't make sense for a particular platform. For example, +/// when implementing a method that only makes sense on a posix-compliant +/// system, implement it on HostInfoPosix, and not on HostInfoBase with a +/// default implementation. This way, users of HostInfo are required to think +/// about the implications of calling a particular method and if used in a +/// context where the method doesn't make sense, will generate a compiler error. +/// +//---------------------------------------------------------------------- + +#if defined(_WIN32) +#include "lldb/Host/windows/HostInfoWindows.h" +#define HOST_INFO_TYPE HostInfoWindows +#elif defined(__linux__) +#if defined(__ANDROID__) +#include "lldb/Host/android/HostInfoAndroid.h" +#define HOST_INFO_TYPE HostInfoAndroid +#else +#include "lldb/Host/linux/HostInfoLinux.h" +#define HOST_INFO_TYPE HostInfoLinux +#endif +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include "lldb/Host/freebsd/HostInfoFreeBSD.h" +#define HOST_INFO_TYPE HostInfoFreeBSD +#elif defined(__NetBSD__) +#include "lldb/Host/netbsd/HostInfoNetBSD.h" +#define HOST_INFO_TYPE HostInfoNetBSD +#elif defined(__OpenBSD__) +#include "lldb/Host/openbsd/HostInfoOpenBSD.h" +#define HOST_INFO_TYPE HostInfoOpenBSD +#elif defined(__APPLE__) +#include "lldb/Host/macosx/HostInfoMacOSX.h" +#define HOST_INFO_TYPE HostInfoMacOSX +#else +#include "lldb/Host/posix/HostInfoPosix.h" +#define HOST_INFO_TYPE HostInfoPosix +#endif + +namespace lldb_private { +typedef HOST_INFO_TYPE HostInfo; +} + +#undef HOST_INFO_TYPE + +#endif diff --git a/include/lldb/Host/HostInfoBase.h b/include/lldb/Host/HostInfoBase.h new file mode 100644 index 000000000..42e3fc3fd --- /dev/null +++ b/include/lldb/Host/HostInfoBase.h @@ -0,0 +1,100 @@ +//===-- HostInfoBase.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_Host_HostInfoBase_h_ +#define lldb_Host_HostInfoBase_h_ + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-enumerations.h" + +#include "llvm/ADT/StringRef.h" + +#include + +#include + +namespace lldb_private { + +class FileSpec; + +class HostInfoBase { +private: + // Static class, unconstructable. + HostInfoBase() {} + ~HostInfoBase() {} + +public: + static void Initialize(); + static void Terminate(); + + //------------------------------------------------------------------ + /// Gets the host target triple as a const string. + /// + /// @return + /// A const string object containing the host target triple. + //------------------------------------------------------------------ + static llvm::StringRef GetTargetTriple(); + + //------------------------------------------------------------------ + /// Gets the host architecture. + /// + /// @return + /// A const architecture object that represents the host + /// architecture. + //------------------------------------------------------------------ + enum ArchitectureKind { + eArchKindDefault, // The overall default architecture that applications will + // run on this host + eArchKind32, // If this host supports 32 bit programs, return the default 32 + // bit arch + eArchKind64 // If this host supports 64 bit programs, return the default 64 + // bit arch + }; + + static const ArchSpec & + GetArchitecture(ArchitectureKind arch_kind = eArchKindDefault); + + //------------------------------------------------------------------ + /// Find a resource files that are related to LLDB. + /// + /// Operating systems have different ways of storing shared + /// libraries and related resources. This function abstracts the + /// access to these paths. + /// + /// @param[in] path_type + /// The type of LLDB resource path you are looking for. If the + /// enumeration ends with "Dir", then only the \a file_spec's + /// directory member gets filled in. + /// + /// @param[in] file_spec + /// A file spec that gets filled in with the appropriate path. + /// + /// @return + /// \b true if \a resource_path was resolved, \a false otherwise. + //------------------------------------------------------------------ + static bool GetLLDBPath(lldb::PathType type, FileSpec &file_spec); + +protected: + static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeProcessTempFileDirectory(FileSpec &file_spec); + static bool ComputeGlobalTempFileDirectory(FileSpec &file_spec); + static bool ComputeTempFileBaseDirectory(FileSpec &file_spec); + static bool ComputeHeaderDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeClangDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/include/lldb/Host/HostNativeProcess.h b/include/lldb/Host/HostNativeProcess.h new file mode 100644 index 000000000..0aabfe197 --- /dev/null +++ b/include/lldb/Host/HostNativeProcess.h @@ -0,0 +1,25 @@ +//===-- HostNativeProcess.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_Host_HostNativeProcess_h_ +#define lldb_Host_HostNativeProcess_h_ + +#if defined(_WIN32) +#include "lldb/Host/windows/HostProcessWindows.h" +namespace lldb_private { +typedef HostProcessWindows HostNativeProcess; +} +#else +#include "lldb/Host/posix/HostProcessPosix.h" +namespace lldb_private { +typedef HostProcessPosix HostNativeProcess; +} +#endif + +#endif diff --git a/include/lldb/Host/HostNativeProcessBase.h b/include/lldb/Host/HostNativeProcessBase.h new file mode 100644 index 000000000..07f98c247 --- /dev/null +++ b/include/lldb/Host/HostNativeProcessBase.h @@ -0,0 +1,48 @@ +//===-- HostNativeProcessBase.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_Host_HostNativeProcessBase_h_ +#define lldb_Host_HostNativeProcessBase_h_ + +#include "lldb/Host/HostProcess.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +class HostThread; + +class HostNativeProcessBase { + DISALLOW_COPY_AND_ASSIGN(HostNativeProcessBase); + +public: + HostNativeProcessBase() : m_process(LLDB_INVALID_PROCESS) {} + explicit HostNativeProcessBase(lldb::process_t process) + : m_process(process) {} + virtual ~HostNativeProcessBase() {} + + virtual Status Terminate() = 0; + virtual Status GetMainModule(FileSpec &file_spec) const = 0; + + virtual lldb::pid_t GetProcessId() const = 0; + virtual bool IsRunning() const = 0; + + lldb::process_t GetSystemHandle() const { return m_process; } + + virtual HostThread + StartMonitoring(const Host::MonitorChildProcessCallback &callback, + bool monitor_signals) = 0; + +protected: + lldb::process_t m_process; +}; +} + +#endif diff --git a/include/lldb/Host/HostNativeThread.h b/include/lldb/Host/HostNativeThread.h new file mode 100644 index 000000000..e33d978d5 --- /dev/null +++ b/include/lldb/Host/HostNativeThread.h @@ -0,0 +1,23 @@ +//===-- HostNativeThread.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_Host_HostNativeThread_h_ +#define lldb_Host_HostNativeThread_h_ + +#include "HostNativeThreadForward.h" + +#if defined(_WIN32) +#include "lldb/Host/windows/HostThreadWindows.h" +#elif defined(__APPLE__) +#include "lldb/Host/macosx/HostThreadMacOSX.h" +#else +#include "lldb/Host/posix/HostThreadPosix.h" +#endif + +#endif diff --git a/include/lldb/Host/HostNativeThreadBase.h b/include/lldb/Host/HostNativeThreadBase.h new file mode 100644 index 000000000..f1f89f3b7 --- /dev/null +++ b/include/lldb/Host/HostNativeThreadBase.h @@ -0,0 +1,52 @@ +//===-- HostNativeThreadBase.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_Host_HostNativeThreadBase_h_ +#define lldb_Host_HostNativeThreadBase_h_ + +#include "lldb/Utility/Status.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +#if defined(_WIN32) +#define THREAD_ROUTINE __stdcall +#else +#define THREAD_ROUTINE +#endif + +class HostNativeThreadBase { + friend class ThreadLauncher; + DISALLOW_COPY_AND_ASSIGN(HostNativeThreadBase); + +public: + HostNativeThreadBase(); + explicit HostNativeThreadBase(lldb::thread_t thread); + virtual ~HostNativeThreadBase() {} + + virtual Status Join(lldb::thread_result_t *result) = 0; + virtual Status Cancel() = 0; + virtual bool IsJoinable() const; + virtual void Reset(); + lldb::thread_t Release(); + + lldb::thread_t GetSystemHandle() const; + lldb::thread_result_t GetResult() const; + +protected: + static lldb::thread_result_t THREAD_ROUTINE + ThreadCreateTrampoline(lldb::thread_arg_t arg); + + lldb::thread_t m_thread; + lldb::thread_result_t m_result; +}; +} + +#endif diff --git a/include/lldb/Host/HostNativeThreadForward.h b/include/lldb/Host/HostNativeThreadForward.h new file mode 100644 index 000000000..4691a22ac --- /dev/null +++ b/include/lldb/Host/HostNativeThreadForward.h @@ -0,0 +1,26 @@ +//===-- HostNativeThreadForward.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_Host_HostNativeThreadForward_h_ +#define lldb_Host_HostNativeThreadForward_h_ + +namespace lldb_private { +#if defined(_WIN32) +class HostThreadWindows; +typedef HostThreadWindows HostNativeThread; +#elif defined(__APPLE__) +class HostThreadMacOSX; +typedef HostThreadMacOSX HostNativeThread; +#else +class HostThreadPosix; +typedef HostThreadPosix HostNativeThread; +#endif +} + +#endif diff --git a/include/lldb/Host/HostProcess.h b/include/lldb/Host/HostProcess.h new file mode 100644 index 000000000..dfc997bd8 --- /dev/null +++ b/include/lldb/Host/HostProcess.h @@ -0,0 +1,60 @@ +//===-- HostProcess.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_Host_HostProcess_h_ +#define lldb_Host_HostProcess_h_ + +#include "lldb/Host/Host.h" +#include "lldb/lldb-types.h" + +//---------------------------------------------------------------------- +/// @class HostInfo HostInfo.h "lldb/Host/HostProcess.h" +/// @brief A class that represents a running process on the host machine. +/// +/// HostProcess allows querying and manipulation of processes running on the +/// host machine. It is not intended to be represent a process which is +/// being debugged, although the native debug engine of a platform may likely +/// back inferior processes by a HostProcess. +/// +/// HostProcess is implemented using static polymorphism so that on any given +/// platform, an instance of HostProcess will always be able to bind statically +/// to the concrete Process implementation for that platform. See HostInfo +/// for more details. +/// +//---------------------------------------------------------------------- + +namespace lldb_private { + +class HostNativeProcessBase; +class HostThread; + +class HostProcess { +public: + HostProcess(); + HostProcess(lldb::process_t process); + ~HostProcess(); + + Status Terminate(); + Status GetMainModule(FileSpec &file_spec) const; + + lldb::pid_t GetProcessId() const; + bool IsRunning() const; + + HostThread StartMonitoring(const Host::MonitorChildProcessCallback &callback, + bool monitor_signals); + + HostNativeProcessBase &GetNativeProcess(); + const HostNativeProcessBase &GetNativeProcess() const; + +private: + std::shared_ptr m_native_process; +}; +} + +#endif diff --git a/include/lldb/Host/HostThread.h b/include/lldb/Host/HostThread.h new file mode 100644 index 000000000..0d2fbe604 --- /dev/null +++ b/include/lldb/Host/HostThread.h @@ -0,0 +1,54 @@ +//===-- HostThread.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_Host_HostThread_h_ +#define lldb_Host_HostThread_h_ + +#include "lldb/Host/HostNativeThreadForward.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-types.h" + +#include + +namespace lldb_private { + +class HostNativeThreadBase; + +//---------------------------------------------------------------------- +/// @class HostInfo HostInfo.h "lldb/Host/HostThread.h" +/// @brief A class that represents a thread running inside of a process on the +/// local machine. +/// +/// HostThread allows querying and manipulation of threads running on the host +/// machine. +/// +//---------------------------------------------------------------------- +class HostThread { +public: + HostThread(); + HostThread(lldb::thread_t thread); + + Status Join(lldb::thread_result_t *result); + Status Cancel(); + void Reset(); + lldb::thread_t Release(); + + bool IsJoinable() const; + HostNativeThread &GetNativeThread(); + const HostNativeThread &GetNativeThread() const; + lldb::thread_result_t GetResult() const; + + bool EqualsThread(lldb::thread_t thread) const; + +private: + std::shared_ptr m_native_thread; +}; +} + +#endif diff --git a/include/lldb/Host/LockFile.h b/include/lldb/Host/LockFile.h new file mode 100644 index 000000000..81cb10c7f --- /dev/null +++ b/include/lldb/Host/LockFile.h @@ -0,0 +1,25 @@ +//===-- LockFile.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_LockFile_h_ +#define liblldb_Host_LockFile_h_ + +#if defined(_WIN32) +#include "lldb/Host/windows/LockFileWindows.h" +namespace lldb_private { +typedef LockFileWindows LockFile; +} +#else +#include "lldb/Host/posix/LockFilePosix.h" +namespace lldb_private { +typedef LockFilePosix LockFile; +} +#endif + +#endif // liblldb_Host_LockFile_h_ diff --git a/include/lldb/Host/LockFileBase.h b/include/lldb/Host/LockFileBase.h new file mode 100644 index 000000000..4eda1916c --- /dev/null +++ b/include/lldb/Host/LockFileBase.h @@ -0,0 +1,57 @@ +//===-- LockFileBase.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_LockFileBase_h_ +#define liblldb_Host_LockFileBase_h_ + +#include "lldb/Utility/Status.h" + +#include + +namespace lldb_private { + +class LockFileBase { +public: + virtual ~LockFileBase() = default; + + bool IsLocked() const; + + Status WriteLock(const uint64_t start, const uint64_t len); + Status TryWriteLock(const uint64_t start, const uint64_t len); + + Status ReadLock(const uint64_t start, const uint64_t len); + Status TryReadLock(const uint64_t start, const uint64_t len); + + Status Unlock(); + +protected: + using Locker = std::function; + + LockFileBase(int fd); + + virtual bool IsValidFile() const; + + virtual Status DoWriteLock(const uint64_t start, const uint64_t len) = 0; + virtual Status DoTryWriteLock(const uint64_t start, const uint64_t len) = 0; + + virtual Status DoReadLock(const uint64_t start, const uint64_t len) = 0; + virtual Status DoTryReadLock(const uint64_t start, const uint64_t len) = 0; + + virtual Status DoUnlock() = 0; + + Status DoLock(const Locker &locker, const uint64_t start, const uint64_t len); + + int m_fd; // not owned. + bool m_locked; + uint64_t m_start; + uint64_t m_len; +}; +} + +#endif diff --git a/include/lldb/Host/MainLoop.h b/include/lldb/Host/MainLoop.h new file mode 100644 index 000000000..5ac145ff8 --- /dev/null +++ b/include/lldb/Host/MainLoop.h @@ -0,0 +1,112 @@ +//===-- MainLoop.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_Host_MainLoop_h_ +#define lldb_Host_MainLoop_h_ + +#include "lldb/Host/Config.h" +#include "lldb/Host/MainLoopBase.h" +#include "llvm/ADT/DenseMap.h" +#include + +#if !HAVE_PPOLL && !HAVE_SYS_EVENT_H +#define SIGNAL_POLLING_UNSUPPORTED 1 +#endif + +namespace lldb_private { + +// Implementation of the MainLoopBase class. It can monitor file descriptors for +// readability using ppoll, kqueue, poll or WSAPoll. On Windows it only supports +// polling sockets, and will not work on generic file handles or pipes. On +// systems without kqueue or ppoll handling singnals is not supported. In +// addition to the common base, this class provides the ability to invoke a +// given handler when a signal is received. +// +// Since this class is primarily intended to be used for single-threaded +// processing, it does not attempt to perform any internal synchronisation and +// any concurrent accesses must be protected externally. However, it is +// perfectly legitimate to have more than one instance of this class running on +// separate threads, or even a single thread (with some limitations on signal +// monitoring). +// TODO: Add locking if this class is to be used in a multi-threaded context. +class MainLoop : public MainLoopBase { +private: + class SignalHandle; + +public: + typedef std::unique_ptr SignalHandleUP; + + MainLoop(); + ~MainLoop() override; + + ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, + const Callback &callback, + Status &error) override; + + // Listening for signals from multiple MainLoop instances is perfectly safe as + // long as they don't try to listen for the same signal. The callback function + // is invoked when the control returns to the Run() function, not when the + // hander is executed. This mean that you can treat the callback as a normal + // function and perform things which would not be safe in a signal handler. + // However, since the callback is not invoked synchronously, you cannot use + // this mechanism to handle SIGSEGV and the like. + SignalHandleUP RegisterSignal(int signo, const Callback &callback, + Status &error); + + Status Run() override; + + // This should only be performed from a callback. Do not attempt to terminate + // the processing from another thread. + // TODO: Add synchronization if we want to be terminated from another thread. + void RequestTermination() override { m_terminate_request = true; } + +protected: + void UnregisterReadObject(IOObject::WaitableHandle handle) override; + + void UnregisterSignal(int signo); + +private: + void ProcessReadObject(IOObject::WaitableHandle handle); + void ProcessSignal(int signo); + + class SignalHandle { + public: + ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } + + private: + SignalHandle(MainLoop &mainloop, int signo) + : m_mainloop(mainloop), m_signo(signo) {} + + MainLoop &m_mainloop; + int m_signo; + + friend class MainLoop; + DISALLOW_COPY_AND_ASSIGN(SignalHandle); + }; + + struct SignalInfo { + Callback callback; +#if HAVE_SIGACTION + struct sigaction old_action; +#endif + bool was_blocked : 1; + }; + class RunImpl; + + llvm::DenseMap m_read_fds; + llvm::DenseMap m_signals; +#if HAVE_SYS_EVENT_H + int m_kqueue; +#endif + bool m_terminate_request : 1; +}; + +} // namespace lldb_private + +#endif // lldb_Host_MainLoop_h_ diff --git a/include/lldb/Host/MainLoopBase.h b/include/lldb/Host/MainLoopBase.h new file mode 100644 index 000000000..a87d262e9 --- /dev/null +++ b/include/lldb/Host/MainLoopBase.h @@ -0,0 +1,93 @@ +//===-- MainLoopBase.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_Host_posix_MainLoopBase_h_ +#define lldb_Host_posix_MainLoopBase_h_ + +#include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Status.h" +#include "llvm/Support/ErrorHandling.h" +#include + +namespace lldb_private { + +// The purpose of this class is to enable multiplexed processing of data from +// different sources +// without resorting to multi-threading. Clients can register IOObjects, which +// will be monitored +// for readability, and when they become ready, the specified callback will be +// invoked. +// Monitoring for writability is not supported, but can be easily added if +// needed. +// +// The RegisterReadObject function return a handle, which controls the duration +// of the monitoring. When +// this handle is destroyed, the callback is deregistered. +// +// This class simply defines the interface common for all platforms, actual +// implementations are +// platform-specific. +class MainLoopBase { +private: + class ReadHandle; + +public: + MainLoopBase() {} + virtual ~MainLoopBase() {} + + typedef std::unique_ptr ReadHandleUP; + + typedef std::function Callback; + + virtual ReadHandleUP RegisterReadObject(const lldb::IOObjectSP &object_sp, + const Callback &callback, + Status &error) { + llvm_unreachable("Not implemented"); + } + + // Waits for registered events and invoke the proper callbacks. Returns when + // all callbacks + // deregister themselves or when someone requests termination. + virtual Status Run() { llvm_unreachable("Not implemented"); } + + // Requests the exit of the Run() function. + virtual void RequestTermination() { llvm_unreachable("Not implemented"); } + +protected: + ReadHandleUP CreateReadHandle(const lldb::IOObjectSP &object_sp) { + return ReadHandleUP(new ReadHandle(*this, object_sp->GetWaitableHandle())); + } + + virtual void UnregisterReadObject(IOObject::WaitableHandle handle) { + llvm_unreachable("Not implemented"); + } + +private: + class ReadHandle { + public: + ~ReadHandle() { m_mainloop.UnregisterReadObject(m_handle); } + + private: + ReadHandle(MainLoopBase &mainloop, IOObject::WaitableHandle handle) + : m_mainloop(mainloop), m_handle(handle) {} + + MainLoopBase &m_mainloop; + IOObject::WaitableHandle m_handle; + + friend class MainLoopBase; + DISALLOW_COPY_AND_ASSIGN(ReadHandle); + }; + +private: + DISALLOW_COPY_AND_ASSIGN(MainLoopBase); +}; + +} // namespace lldb_private + +#endif // lldb_Host_posix_MainLoopBase_h_ diff --git a/include/lldb/Host/MonitoringProcessLauncher.h b/include/lldb/Host/MonitoringProcessLauncher.h new file mode 100644 index 000000000..9ad36e90a --- /dev/null +++ b/include/lldb/Host/MonitoringProcessLauncher.h @@ -0,0 +1,36 @@ +//===-- MonitoringProcessLauncher.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_Host_MonitoringProcessLauncher_h_ +#define lldb_Host_MonitoringProcessLauncher_h_ + +// C Includes +// C++ Includes +#include +// Other libraries and framework includes +// Project includes +#include "lldb/Host/ProcessLauncher.h" + +namespace lldb_private { + +class MonitoringProcessLauncher : public ProcessLauncher { +public: + explicit MonitoringProcessLauncher( + std::unique_ptr delegate_launcher); + + HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, + Status &error) override; + +private: + std::unique_ptr m_delegate_launcher; +}; + +} // namespace lldb_private + +#endif // lldb_Host_MonitoringProcessLauncher_h_ diff --git a/include/lldb/Host/OptionParser.h b/include/lldb/Host/OptionParser.h new file mode 100644 index 000000000..1b0dc4ae1 --- /dev/null +++ b/include/lldb/Host/OptionParser.h @@ -0,0 +1,51 @@ +//===-- OptionParser.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionParser_h_ +#define liblldb_OptionParser_h_ + +#include +#include + +#include "llvm/ADT/StringRef.h" + +struct option; + +namespace lldb_private { + +struct OptionDefinition; + +struct Option { + // The definition of the option that this refers to. + const OptionDefinition *definition; + // if not NULL, set *flag to val when option found + int *flag; + // if flag not NULL, value to set *flag to; else return value + int val; +}; + +class OptionParser { +public: + enum OptionArgument { eNoArgument = 0, eRequiredArgument, eOptionalArgument }; + + static void Prepare(std::unique_lock &lock); + + static void EnableError(bool error); + + static int Parse(int argc, char *const argv[], llvm::StringRef optstring, + const Option *longopts, int *longindex); + + static char *GetOptionArgument(); + static int GetOptionIndex(); + static int GetOptionErrorCause(); + static std::string GetShortOptionString(struct option *long_options); +}; +} + +#endif // liblldb_OptionParser_h_ diff --git a/include/lldb/Host/Pipe.h b/include/lldb/Host/Pipe.h new file mode 100644 index 000000000..283fb1b83 --- /dev/null +++ b/include/lldb/Host/Pipe.h @@ -0,0 +1,25 @@ +//===-- Pipe.h --------------------------------------------------*- 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_Pipe_h_ +#define liblldb_Host_Pipe_h_ + +#if defined(_WIN32) +#include "lldb/Host/windows/PipeWindows.h" +namespace lldb_private { +typedef PipeWindows Pipe; +} +#else +#include "lldb/Host/posix/PipePosix.h" +namespace lldb_private { +typedef PipePosix Pipe; +} +#endif + +#endif // liblldb_Host_Pipe_h_ diff --git a/include/lldb/Host/PipeBase.h b/include/lldb/Host/PipeBase.h new file mode 100644 index 000000000..ad62072c7 --- /dev/null +++ b/include/lldb/Host/PipeBase.h @@ -0,0 +1,65 @@ +//===-- PipeBase.h -----------------------------------------------*- 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_PipeBase_h_ +#define liblldb_Host_PipeBase_h_ + +#include +#include + +#include "lldb/Utility/Status.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { +class PipeBase { +public: + virtual ~PipeBase(); + + virtual Status CreateNew(bool child_process_inherit) = 0; + virtual Status CreateNew(llvm::StringRef name, + bool child_process_inherit) = 0; + virtual Status CreateWithUniqueName(llvm::StringRef prefix, + bool child_process_inherit, + llvm::SmallVectorImpl &name) = 0; + + virtual Status OpenAsReader(llvm::StringRef name, + bool child_process_inherit) = 0; + + Status OpenAsWriter(llvm::StringRef name, bool child_process_inherit); + virtual Status + OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, + const std::chrono::microseconds &timeout) = 0; + + virtual bool CanRead() const = 0; + virtual bool CanWrite() const = 0; + + virtual int GetReadFileDescriptor() const = 0; + virtual int GetWriteFileDescriptor() const = 0; + virtual int ReleaseReadFileDescriptor() = 0; + virtual int ReleaseWriteFileDescriptor() = 0; + virtual void CloseReadFileDescriptor() = 0; + virtual void CloseWriteFileDescriptor() = 0; + + // Close both descriptors + virtual void Close() = 0; + + // Delete named pipe. + virtual Status Delete(llvm::StringRef name) = 0; + + virtual Status Write(const void *buf, size_t size, size_t &bytes_written) = 0; + virtual Status ReadWithTimeout(void *buf, size_t size, + const std::chrono::microseconds &timeout, + size_t &bytes_read) = 0; + Status Read(void *buf, size_t size, size_t &bytes_read); +}; +} + +#endif diff --git a/include/lldb/Host/PosixApi.h b/include/lldb/Host/PosixApi.h new file mode 100644 index 000000000..d5c48dd6d --- /dev/null +++ b/include/lldb/Host/PosixApi.h @@ -0,0 +1,23 @@ +//===-- PosixApi.h ----------------------------------------------*- 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_PosixApi_h +#define liblldb_Host_PosixApi_h + +// This file defines platform specific functions, macros, and types necessary +// to provide a minimum level of compatibility across all platforms to rely +// on various posix api functionality. + +#if defined(_WIN32) +#include "lldb/Host/windows/PosixApi.h" +#else +#include +#endif + +#endif diff --git a/include/lldb/Host/Predicate.h b/include/lldb/Host/Predicate.h new file mode 100644 index 000000000..3ee27e74b --- /dev/null +++ b/include/lldb/Host/Predicate.h @@ -0,0 +1,524 @@ +//===-- 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_ + +// C Includes +#include +#include + +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-defines.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 Predicate { +public: + //------------------------------------------------------------------ + /// Default constructor. + /// + /// Initializes the mutex, condition and value with their default + /// constructors. + //------------------------------------------------------------------ + Predicate() : m_value(), m_mutex(), m_condition() {} + + //------------------------------------------------------------------ + /// Construct with initial T value \a initial_value. + /// + /// Initializes the mutex and condition with their default + /// constructors, and initializes the value with \a initial_value. + /// + /// @param[in] initial_value + /// The initial value for our T object. + //------------------------------------------------------------------ + Predicate(T initial_value) + : m_value(initial_value), m_mutex(), m_condition() {} + + //------------------------------------------------------------------ + /// Destructor. + /// + /// Destroy the condition, mutex, and T objects. + //------------------------------------------------------------------ + ~Predicate() = default; + + //------------------------------------------------------------------ + /// 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 { + std::lock_guard guard(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 broadcast. See the + /// PredicateBroadcastType enumeration for details. + /// + /// @see Predicate::Broadcast() + //------------------------------------------------------------------ + void SetValue(T value, PredicateBroadcastType broadcast_type) { + std::lock_guard guard(m_mutex); +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, + broadcast_type); +#endif + const T old_value = m_value; + m_value = value; + + Broadcast(old_value, broadcast_type); + } + + //------------------------------------------------------------------ + /// Set some bits in \a m_value. + /// + /// Logically set the bits \a bits in the contained \a m_value in a + /// thread safe way and broadcast if needed. + /// + /// @param[in] bits + /// The bits to set in \a m_value. + /// + /// @param[in] broadcast_type + /// A value indicating when and if to broadcast. See the + /// PredicateBroadcastType enumeration for details. + /// + /// @see Predicate::Broadcast() + //------------------------------------------------------------------ + void SetValueBits(T bits, PredicateBroadcastType broadcast_type) { + std::lock_guard guard(m_mutex); +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, + broadcast_type); +#endif + const T old_value = m_value; + m_value |= bits; + + Broadcast(old_value, broadcast_type); + } + + //------------------------------------------------------------------ + /// Reset some bits in \a m_value. + /// + /// Logically reset (clear) the bits \a bits in the contained + /// \a m_value in a thread safe way and broadcast if needed. + /// + /// @param[in] bits + /// The bits to clear in \a m_value. + /// + /// @param[in] broadcast_type + /// A value indicating when and if to broadcast. See the + /// PredicateBroadcastType enumeration for details. + /// + /// @see Predicate::Broadcast() + //------------------------------------------------------------------ + void ResetValueBits(T bits, PredicateBroadcastType broadcast_type) { + std::lock_guard guard(m_mutex); +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, + broadcast_type); +#endif + const T old_value = m_value; + m_value &= ~bits; + + Broadcast(old_value, broadcast_type); + } + + //------------------------------------------------------------------ + /// Wait for bits to be set in \a m_value. + /// + /// Waits in a thread safe way for any bits in \a bits to get + /// logically set in \a m_value. If any bits are already set in + /// \a m_value, this function will return without waiting. + /// + /// It is possible for the value to be changed between the time + /// the bits are set and the time the waiting thread wakes up. + /// If the bits are no longer set when the waiting thread wakes + /// up, it will go back into a wait state. It may be necessary + /// for the calling code to use additional thread synchronization + /// methods to detect transitory states. + /// + /// @param[in] bits + /// The bits we are waiting to be set in \a m_value. + /// + /// @param[in] abstime + /// If non-nullptr, 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 std::chrono::microseconds &timeout = + std::chrono::microseconds(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 (std::lock_guard) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + std::unique_lock lock(m_mutex); +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (bits = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n", + __FUNCTION__, bits, timeout.count(), m_value); +#endif + while ((m_value & bits) == 0) { + if (timeout == std::chrono::microseconds(0)) { + m_condition.wait(lock); + } else { + std::cv_status result = m_condition.wait_for(lock, timeout); + if (result == std::cv_status::timeout) + break; + } + } +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", + __FUNCTION__, bits, m_value, m_value & bits); +#endif + + return m_value & bits; + } + + //------------------------------------------------------------------ + /// Wait for bits to be reset in \a m_value. + /// + /// Waits in a thread safe way for any bits in \a bits to get + /// logically reset in \a m_value. If all bits are already reset in + /// \a m_value, this function will return without waiting. + /// + /// It is possible for the value to be changed between the time + /// the bits are reset and the time the waiting thread wakes up. + /// If the bits are no set when the waiting thread wakes up, it will + /// go back into a wait state. It may be necessary for the calling + /// code to use additional thread synchronization methods to detect + /// transitory states. + /// + /// @param[in] bits + /// The bits we are waiting to be reset in \a m_value. + /// + /// @param[in] abstime + /// If non-nullptr, 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 std::chrono::microseconds &timeout = + std::chrono::microseconds(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 (std::lock_guard) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + std::unique_lock lock(m_mutex); + +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (bits = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n", + __FUNCTION__, bits, timeout.count(), m_value); +#endif + while ((m_value & bits) != 0) { + if (timeout == std::chrono::microseconds(0)) { + m_condition.wait(lock); + } else { + std::cv_status result = m_condition.wait_for(lock, timeout); + if (result == std::cv_status::timeout) + break; + } + } + +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", + __FUNCTION__, bits, m_value, m_value & bits); +#endif + return m_value & bits; + } + + //------------------------------------------------------------------ + /// Wait for \a m_value to be equal to \a value. + /// + /// Waits in a thread safe way for \a m_value to be equal to \a + /// value. If \a m_value is already equal to \a value, this + /// function will return without waiting. + /// + /// It is possible for the value to be changed between the time + /// the value is set and the time the waiting thread wakes up. + /// If the value no longer matches the requested value when the + /// waiting thread wakes up, it will go back into a wait state. It + /// may be necessary for the calling code to use additional thread + /// synchronization methods to detect transitory states. + /// + /// @param[in] value + /// The value we want \a m_value to be equal to. + /// + /// @param[in] abstime + /// If non-nullptr, 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 std::chrono::microseconds &timeout = + std::chrono::microseconds(0), + bool *timed_out = nullptr) { + // 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 (std::lock_guard) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + std::unique_lock lock(m_mutex); + +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (value = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n", + __FUNCTION__, value, timeout.count(), m_value); +#endif + if (timed_out) + *timed_out = false; + + while (m_value != value) { + if (timeout == std::chrono::microseconds(0)) { + m_condition.wait(lock); + } else { + std::cv_status result = m_condition.wait_for(lock, timeout); + if (result == std::cv_status::timeout) { + if (timed_out) + *timed_out = true; + break; + } + } + } + + return m_value == value; + } + + //------------------------------------------------------------------ + /// Wait for \a m_value to be equal to \a value and then set it to + /// a new value. + /// + /// Waits in a thread safe way for \a m_value to be equal to \a + /// value and then sets \a m_value to \a new_value. If \a m_value + /// is already equal to \a value, this function will immediately + /// set \a m_value to \a new_value and return without waiting. + /// + /// It is possible for the value to be changed between the time + /// the value is set and the time the waiting thread wakes up. + /// If the value no longer matches the requested value when the + /// waiting thread wakes up, it will go back into a wait state. It + /// may be necessary for the calling code to use additional thread + /// synchronization methods to detect transitory states. + /// + /// @param[in] value + /// The value we want \a m_value to be equal to. + /// + /// @param[in] new_value + /// The value to which \a m_value will be set if \b true is + /// returned. + /// + /// @param[in] abstime + /// If non-nullptr, the absolute time at which we should stop + /// waiting, else wait an infinite amount of time. + /// + /// @param[out] timed_out + /// If not null, set to true if we return because of a time out, + /// and false if the value was set. + /// + /// @return + /// @li \b true if the \a m_value became equal to \a value + /// @li \b false otherwise + //------------------------------------------------------------------ + bool WaitForValueEqualToAndSetValueTo( + T wait_value, T new_value, + const std::chrono::microseconds &timeout = std::chrono::microseconds(0), + bool *timed_out = nullptr) { + // 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 (std::lock_guard) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + std::unique_lock lock(m_mutex); + +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (wait_value = 0x%8.8x, new_value = 0x%8.8x, timeout = %llu), " + "m_value = 0x%8.8x\n", + __FUNCTION__, wait_value, new_value, timeout.count(), m_value); +#endif + if (timed_out) + *timed_out = false; + + while (m_value != wait_value) { + if (timeout == std::chrono::microseconds(0)) { + m_condition.wait(lock); + } else { + std::cv_status result = m_condition.wait_for(lock, timeout); + if (result == std::cv_status::timeout) { + if (timed_out) + *timed_out = true; + break; + } + } + } + + if (m_value == wait_value) { + m_value = new_value; + return true; + } + + return false; + } + + //------------------------------------------------------------------ + /// Wait for \a m_value to not be equal to \a value. + /// + /// Waits in a thread safe way for \a m_value to not be equal to \a + /// value. If \a m_value is already not equal to \a value, this + /// function will return without waiting. + /// + /// It is possible for the value to be changed between the time + /// the value is set and the time the waiting thread wakes up. + /// If the value is equal to the test value when the waiting thread + /// wakes up, it will go back into a wait state. It may be + /// necessary for the calling code to use additional thread + /// synchronization methods to detect transitory states. + /// + /// @param[in] value + /// The value we want \a m_value to not be equal to. + /// + /// @param[out] new_value + /// The new value if \b true is returned. + /// + /// @param[in] abstime + /// If non-nullptr, 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 std::chrono::microseconds &timeout = std::chrono::microseconds(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 (std::lock_guard) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + std::unique_lock lock(m_mutex); +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (value = 0x%8.8x, timeout = %llu), m_value = 0x%8.8x\n", + __FUNCTION__, value, timeout.count(), m_value); +#endif + while (m_value == value) { + if (timeout == std::chrono::microseconds(0)) { + m_condition.wait(lock); + } else { + std::cv_status result = m_condition.wait_for(lock, timeout); + if (result == std::cv_status::timeout) + break; + } + } + + if (m_value != value) { + new_value = m_value; + return true; + } + return false; + } + +protected: + //---------------------------------------------------------------------- + // pthread condition and mutex variable to control 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 std::mutex m_mutex; ///< The mutex to use when accessing the data + std::condition_variable 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 + /// depending on the \a old_value and on the \a broadcast_type. + /// + /// If \a broadcast_type is eBroadcastNever, no broadcast will be + /// sent. + /// + /// If \a broadcast_type is eBroadcastAlways, the condition variable + /// will always be broadcast. + /// + /// If \a broadcast_type is eBroadcastOnChange, the condition + /// variable be broadcast if the owned value changes. + //------------------------------------------------------------------ + void Broadcast(T old_value, PredicateBroadcastType broadcast_type) { + bool broadcast = + (broadcast_type == eBroadcastAlways) || + ((broadcast_type == eBroadcastOnChange) && old_value != m_value); +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, " + "broadcast = %u\n", + __FUNCTION__, old_value, broadcast_type, m_value, broadcast); +#endif + if (broadcast) + m_condition.notify_all(); + } + + DISALLOW_COPY_AND_ASSIGN(Predicate); +}; + +} // namespace lldb_private + +#endif // liblldb_Predicate_h_ diff --git a/include/lldb/Host/ProcessLauncher.h b/include/lldb/Host/ProcessLauncher.h new file mode 100644 index 000000000..49fa84113 --- /dev/null +++ b/include/lldb/Host/ProcessLauncher.h @@ -0,0 +1,27 @@ +//===-- ProcessLauncher.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_Host_ProcessLauncher_h_ +#define lldb_Host_ProcessLauncher_h_ + +namespace lldb_private { + +class ProcessLaunchInfo; +class Status; +class HostProcess; + +class ProcessLauncher { +public: + virtual ~ProcessLauncher() {} + virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, + Status &error) = 0; +}; +} + +#endif diff --git a/include/lldb/Host/ProcessRunLock.h b/include/lldb/Host/ProcessRunLock.h new file mode 100644 index 000000000..7044fdbd9 --- /dev/null +++ b/include/lldb/Host/ProcessRunLock.h @@ -0,0 +1,92 @@ +//===-- ProcessRunLock.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ProcessRunLock_h_ +#define liblldb_ProcessRunLock_h_ + +// C Includes +#include +#include + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-defines.h" + +//---------------------------------------------------------------------- +/// Enumerations for broadcasting. +//---------------------------------------------------------------------- +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class ProcessRunLock ProcessRunLock.h "lldb/Host/ProcessRunLock.h" +/// @brief A class used to prevent the process from starting while other +/// threads are accessing its data, and prevent access to its data while +/// it is running. +//---------------------------------------------------------------------- + +class ProcessRunLock { +public: + ProcessRunLock(); + ~ProcessRunLock(); + + bool ReadTryLock(); + bool ReadUnlock(); + bool SetRunning(); + bool TrySetRunning(); + bool SetStopped(); + + class ProcessRunLocker { + public: + ProcessRunLocker() : m_lock(nullptr) {} + + ~ProcessRunLocker() { Unlock(); } + + // Try to lock the read lock, but only do so if there are no writers. + bool TryLock(ProcessRunLock *lock) { + if (m_lock) { + if (m_lock == lock) + return true; // We already have this lock locked + else + Unlock(); + } + if (lock) { + if (lock->ReadTryLock()) { + m_lock = lock; + return true; + } + } + return false; + } + + protected: + void Unlock() { + if (m_lock) { + m_lock->ReadUnlock(); + m_lock = nullptr; + } + } + + ProcessRunLock *m_lock; + + private: + DISALLOW_COPY_AND_ASSIGN(ProcessRunLocker); + }; + +protected: + lldb::rwlock_t m_rwlock; + bool m_running; + +private: + DISALLOW_COPY_AND_ASSIGN(ProcessRunLock); +}; + +} // namespace lldb_private + +#endif // liblldb_ProcessRunLock_h_ diff --git a/include/lldb/Host/PseudoTerminal.h b/include/lldb/Host/PseudoTerminal.h new file mode 100644 index 000000000..fdbf6df1a --- /dev/null +++ b/include/lldb/Host/PseudoTerminal.h @@ -0,0 +1,252 @@ +//===-- 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 LLDB_HOST_PSEUDOTERMINAL_H +#define LLDB_HOST_PSEUDOTERMINAL_H +#if defined(__cplusplus) + +#include +#include + +#include "lldb/lldb-defines.h" + +namespace lldb_utility { + +//---------------------------------------------------------------------- +/// @class PseudoTerminal PseudoTerminal.h "lldb/Host/PseudoTerminal.h" +/// @brief A pseudo terminal helper class. +/// +/// The pseudo terminal class abstracts 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 ownership has not been released using + /// one of: + /// @li PseudoTerminal::ReleaseMasterFileDescriptor() + /// @li PseudoTerminal::ReleaseSaveFileDescriptor() + //------------------------------------------------------------------ + ~PseudoTerminal(); + + //------------------------------------------------------------------ + /// Close the master file descriptor if it is valid. + //------------------------------------------------------------------ + void CloseMasterFileDescriptor(); + + //------------------------------------------------------------------ + /// Close the slave file descriptor if it is valid. + //------------------------------------------------------------------ + void CloseSlaveFileDescriptor(); + + //------------------------------------------------------------------ + /// Fork a child process that uses pseudo terminals for its stdio. + /// + /// In the parent process, a call to this function results in a pid + /// being returned. If the pid is valid, the master file descriptor + /// can be used for read/write access to stdio of the child process. + /// + /// In the child process the stdin/stdout/stderr will already be + /// routed to the slave pseudo terminal and the master file + /// descriptor will be closed as it is no longer needed by the child + /// process. + /// + /// This class will close the file descriptors for the master/slave + /// when the destructor is called. The file handles can be released + /// using either: + /// @li PseudoTerminal::ReleaseMasterFileDescriptor() + /// @li PseudoTerminal::ReleaseSaveFileDescriptor() + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// @li \b Parent process: a child process ID that is greater + /// than zero, or -1 if the fork fails. + /// @li \b Child process: zero. + //------------------------------------------------------------------ + lldb::pid_t Fork(char *error_str, size_t error_len); + + //------------------------------------------------------------------ + /// The master file descriptor accessor. + /// + /// This object retains ownership of the master file descriptor when + /// this accessor is used. Users can call the member function + /// PseudoTerminal::ReleaseMasterFileDescriptor() if this + /// object should release ownership of the slave file descriptor. + /// + /// @return + /// The master file descriptor, or PseudoTerminal::invalid_fd + /// if the master file descriptor is not currently valid. + /// + /// @see PseudoTerminal::ReleaseMasterFileDescriptor() + //------------------------------------------------------------------ + int GetMasterFileDescriptor() const; + + //------------------------------------------------------------------ + /// The slave file descriptor accessor. + /// + /// This object retains ownership of the slave file descriptor when + /// this accessor is used. Users can call the member function + /// PseudoTerminal::ReleaseSlaveFileDescriptor() if this + /// object should release ownership of the slave file descriptor. + /// + /// @return + /// The slave file descriptor, or PseudoTerminal::invalid_fd + /// if the slave file descriptor is not currently valid. + /// + /// @see PseudoTerminal::ReleaseSlaveFileDescriptor() + //------------------------------------------------------------------ + int GetSlaveFileDescriptor() const; + + //------------------------------------------------------------------ + /// Get the name of the slave pseudo terminal. + /// + /// A master pseudo terminal should already be valid prior to + /// calling this function. + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// The name of the slave pseudo terminal as a NULL terminated + /// C. This string that comes from static memory, so a copy of + /// the string should be made as subsequent calls can change + /// this value. NULL is returned if this object doesn't have + /// a valid master pseudo terminal opened or if the call to + /// \c ptsname() fails. + /// + /// @see PseudoTerminal::OpenFirstAvailableMaster() + //------------------------------------------------------------------ + const char *GetSlaveName(char *error_str, size_t error_len) const; + + //------------------------------------------------------------------ + /// Open the first available pseudo terminal. + /// + /// Opens the first available pseudo terminal with \a oflag as the + /// permissions. The opened master file descriptor is stored in this + /// object and can be accessed by calling the + /// PseudoTerminal::GetMasterFileDescriptor() accessor. Clients + /// can call the PseudoTerminal::ReleaseMasterFileDescriptor() + /// accessor function if they wish to use the master file descriptor + /// beyond the lifespan of this object. + /// + /// If this object still has a valid master file descriptor when its + /// destructor is called, it will close it. + /// + /// @param[in] oflag + /// Flags to use when calling \c posix_openpt(\a oflag). + /// A value of "O_RDWR|O_NOCTTY" is suggested. + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// @li \b true when the 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 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_utility + +#endif // #if defined(__cplusplus) +#endif // #ifndef liblldb_PseudoTerminal_h_ diff --git a/include/lldb/Host/Socket.h b/include/lldb/Host/Socket.h new file mode 100644 index 000000000..37f468f23 --- /dev/null +++ b/include/lldb/Host/Socket.h @@ -0,0 +1,126 @@ +//===-- Socket.h ------------------------------------------------*- 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_Socket_h_ +#define liblldb_Host_Socket_h_ + +#include +#include + +#include "lldb/lldb-private.h" + +#include "lldb/Host/Predicate.h" +#include "lldb/Host/SocketAddress.h" +#include "lldb/Utility/IOObject.h" +#include "lldb/Utility/Status.h" + +#ifdef _WIN32 +#include "lldb/Host/windows/windows.h" +#include +#include +#endif + +namespace llvm { +class StringRef; +} + +namespace lldb_private { + +#if defined(_MSC_VER) +typedef SOCKET NativeSocket; +#else +typedef int NativeSocket; +#endif + +class Socket : public IOObject { +public: + typedef enum { + ProtocolTcp, + ProtocolUdp, + ProtocolUnixDomain, + ProtocolUnixAbstract + } SocketProtocol; + + static const NativeSocket kInvalidSocketValue; + + ~Socket() override; + + static std::unique_ptr Create(const SocketProtocol protocol, + bool child_processes_inherit, + Status &error); + + virtual Status Connect(llvm::StringRef name) = 0; + virtual Status Listen(llvm::StringRef name, int backlog) = 0; + virtual Status Accept(Socket *&socket) = 0; + + // Initialize a Tcp Socket object in listening mode. listen and accept are + // implemented + // separately because the caller may wish to manipulate or query the socket + // after it is + // initialized, but before entering a blocking accept. + static Status TcpListen(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&socket, + Predicate *predicate, int backlog = 5); + static Status TcpConnect(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&socket); + static Status UdpConnect(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&socket); + static Status UnixDomainConnect(llvm::StringRef host_and_port, + bool child_processes_inherit, + Socket *&socket); + static Status UnixDomainAccept(llvm::StringRef host_and_port, + bool child_processes_inherit, Socket *&socket); + static Status UnixAbstractConnect(llvm::StringRef host_and_port, + bool child_processes_inherit, + Socket *&socket); + static Status UnixAbstractAccept(llvm::StringRef host_and_port, + bool child_processes_inherit, + Socket *&socket); + + int GetOption(int level, int option_name, int &option_value); + int SetOption(int level, int option_name, int option_value); + + NativeSocket GetNativeSocket() const { return m_socket; } + SocketProtocol GetSocketProtocol() const { return m_protocol; } + + Status Read(void *buf, size_t &num_bytes) override; + Status Write(const void *buf, size_t &num_bytes) override; + + virtual Status PreDisconnect(); + Status Close() override; + + bool IsValid() const override { return m_socket != kInvalidSocketValue; } + WaitableHandle GetWaitableHandle() override; + + static bool DecodeHostAndPort(llvm::StringRef host_and_port, + std::string &host_str, std::string &port_str, + int32_t &port, Status *error_ptr); + +protected: + Socket(SocketProtocol protocol, bool should_close, + bool m_child_process_inherit); + + virtual size_t Send(const void *buf, const size_t num_bytes); + + static void SetLastError(Status &error); + static NativeSocket CreateSocket(const int domain, const int type, + const int protocol, + bool child_processes_inherit, Status &error); + static NativeSocket AcceptSocket(NativeSocket sockfd, struct sockaddr *addr, + socklen_t *addrlen, + bool child_processes_inherit, Status &error); + + SocketProtocol m_protocol; + NativeSocket m_socket; + bool m_child_processes_inherit; +}; + +} // namespace lldb_private + +#endif // liblldb_Host_Socket_h_ diff --git a/include/lldb/Host/SocketAddress.h b/include/lldb/Host/SocketAddress.h new file mode 100644 index 000000000..ebc6f4e57 --- /dev/null +++ b/include/lldb/Host/SocketAddress.h @@ -0,0 +1,236 @@ +//===-- SocketAddress.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_SocketAddress_h_ +#define liblldb_SocketAddress_h_ + +// C Includes +#include + +#ifdef _WIN32 +#include "lldb/Host/windows/windows.h" +#include +#include +typedef ADDRESS_FAMILY sa_family_t; +#else +#include +#include +#include +#endif + +#if defined(__FreeBSD__) +#include +#endif + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include +#include + +namespace lldb_private { + +class SocketAddress { +public: + //---------------------------------------------------------------------------- + // Static method to get all address information for a host and/or service + //---------------------------------------------------------------------------- + static std::vector + GetAddressInfo(const char *hostname, const char *servname, int ai_family, + int ai_socktype, int ai_protocol, int ai_flags = 0); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SocketAddress(); + SocketAddress(const struct addrinfo *addr_info); + SocketAddress(const struct sockaddr &s); + SocketAddress(const struct sockaddr_in &s); + SocketAddress(const struct sockaddr_in6 &s); + SocketAddress(const struct sockaddr_storage &s); + SocketAddress(const SocketAddress &rhs); + ~SocketAddress(); + + //------------------------------------------------------------------ + // Operators + //------------------------------------------------------------------ + const SocketAddress &operator=(const SocketAddress &rhs); + + const SocketAddress &operator=(const struct addrinfo *addr_info); + + const SocketAddress &operator=(const struct sockaddr &s); + + const SocketAddress &operator=(const struct sockaddr_in &s); + + const SocketAddress &operator=(const struct sockaddr_in6 &s); + + const SocketAddress &operator=(const struct sockaddr_storage &s); + + bool operator==(const SocketAddress &rhs) const; + bool operator!=(const SocketAddress &rhs) const; + + //------------------------------------------------------------------ + // Clear the contents of this socket address + //------------------------------------------------------------------ + void Clear(); + + //------------------------------------------------------------------ + // Get the length for the current socket address family + //------------------------------------------------------------------ + socklen_t GetLength() const; + + //------------------------------------------------------------------ + // Get the max length for the largest socket address supported. + //------------------------------------------------------------------ + static socklen_t GetMaxLength(); + + //------------------------------------------------------------------ + // Get the socket address family + //------------------------------------------------------------------ + sa_family_t GetFamily() const; + + //------------------------------------------------------------------ + // Set the socket address family + //------------------------------------------------------------------ + void SetFamily(sa_family_t family); + + //------------------------------------------------------------------ + // Get the address + //------------------------------------------------------------------ + std::string GetIPAddress() const; + + //------------------------------------------------------------------ + // Get the port if the socket address for the family has a port + //------------------------------------------------------------------ + uint16_t GetPort() const; + + //------------------------------------------------------------------ + // Set the port if the socket address for the family has a port. + // The family must be set correctly prior to calling this function. + //------------------------------------------------------------------ + bool SetPort(uint16_t port); + + //------------------------------------------------------------------ + // Set the socket address according to the first match from a call + // to getaddrinfo() (or equivalent functions for systems that don't + // have getaddrinfo(). If "addr_info_ptr" is not NULL, it will get + // filled in with the match that was used to populate this socket + // address. + //------------------------------------------------------------------ + bool + getaddrinfo(const char *host, // Hostname ("foo.bar.com" or "foo" or IP + // address string ("123.234.12.1" or + // "2001:0db8:85a3:0000:0000:8a2e:0370:7334") + const char *service, // Protocol name ("tcp", "http", etc) or a + // raw port number string ("81") + int ai_family = PF_UNSPEC, int ai_socktype = 0, + int ai_protocol = 0, int ai_flags = 0); + + //------------------------------------------------------------------ + // Quick way to set the SocketAddress to localhost given the family. + // Returns true if successful, false if "family" doesn't support + // localhost or if "family" is not supported by this class. + //------------------------------------------------------------------ + bool SetToLocalhost(sa_family_t family, uint16_t port); + + bool SetToAnyAddress(sa_family_t family, uint16_t port); + + //------------------------------------------------------------------ + // Returns true if there is a valid socket address in this object. + //------------------------------------------------------------------ + bool IsValid() const; + + //------------------------------------------------------------------ + // Returns true if the socket is INADDR_ANY + //------------------------------------------------------------------ + bool IsAnyAddr() const; + + //------------------------------------------------------------------ + // Returns true if the socket is INADDR_LOOPBACK + //------------------------------------------------------------------ + bool IsLocalhost() const; + + //------------------------------------------------------------------ + // Direct access to all of the sockaddr structures + //------------------------------------------------------------------ + struct sockaddr &sockaddr() { + return m_socket_addr.sa; + } + + const struct sockaddr &sockaddr() const { return m_socket_addr.sa; } + + struct sockaddr_in &sockaddr_in() { + return m_socket_addr.sa_ipv4; + } + + const struct sockaddr_in &sockaddr_in() const { + return m_socket_addr.sa_ipv4; + } + + struct sockaddr_in6 &sockaddr_in6() { + return m_socket_addr.sa_ipv6; + } + + const struct sockaddr_in6 &sockaddr_in6() const { + return m_socket_addr.sa_ipv6; + } + + struct sockaddr_storage &sockaddr_storage() { + return m_socket_addr.sa_storage; + } + + const struct sockaddr_storage &sockaddr_storage() const { + return m_socket_addr.sa_storage; + } + + //------------------------------------------------------------------ + // Conversion operators to allow getting the contents of this class + // as a pointer to the appropriate structure. This allows an instance + // of this class to be used in calls that take one of the sockaddr + // structure variants without having to manually use the correct + // accessor function. + //------------------------------------------------------------------ + + operator struct sockaddr *() { return &m_socket_addr.sa; } + + operator const struct sockaddr *() const { return &m_socket_addr.sa; } + + operator struct sockaddr_in *() { return &m_socket_addr.sa_ipv4; } + + operator const struct sockaddr_in *() const { return &m_socket_addr.sa_ipv4; } + + operator struct sockaddr_in6 *() { return &m_socket_addr.sa_ipv6; } + + operator const struct sockaddr_in6 *() const { + return &m_socket_addr.sa_ipv6; + } + + operator const struct sockaddr_storage *() const { + return &m_socket_addr.sa_storage; + } + + operator struct sockaddr_storage *() { return &m_socket_addr.sa_storage; } + +protected: + typedef union sockaddr_tag { + struct sockaddr sa; + struct sockaddr_in sa_ipv4; + struct sockaddr_in6 sa_ipv6; + struct sockaddr_storage sa_storage; + } sockaddr_t; + + //------------------------------------------------------------------ + // Classes that inherit from SocketAddress can see and modify these + //------------------------------------------------------------------ + sockaddr_t m_socket_addr; +}; + +} // namespace lldb_private + +#endif // liblldb_SocketAddress_h_ diff --git a/include/lldb/Host/StringConvert.h b/include/lldb/Host/StringConvert.h new file mode 100644 index 000000000..05bd7808e --- /dev/null +++ b/include/lldb/Host/StringConvert.h @@ -0,0 +1,47 @@ +//===-- StringConvert.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_StringConvert_h_ +#define liblldb_StringConvert_h_ + +// C Includes +#include + +// C++ Includes + +// Other libraries and framework includes +// Project includes + +namespace lldb_private { + +namespace StringConvert { + +//---------------------------------------------------------------------- +/// @namespace StringConvert StringConvert.h "lldb/Host/StringConvert.h" +/// @brief Utility classes for converting strings into Integers +//---------------------------------------------------------------------- + +int32_t ToSInt32(const char *s, int32_t fail_value = 0, int base = 0, + bool *success_ptr = nullptr); + +uint32_t ToUInt32(const char *s, uint32_t fail_value = 0, int base = 0, + bool *success_ptr = nullptr); + +int64_t ToSInt64(const char *s, int64_t fail_value = 0, int base = 0, + bool *success_ptr = nullptr); + +uint64_t ToUInt64(const char *s, uint64_t fail_value = 0, int base = 0, + bool *success_ptr = nullptr); + +double ToDouble(const char *s, double fail_value = 0.0, + bool *success_ptr = nullptr); +} // namespace StringConvert +} // namespace lldb_private + +#endif diff --git a/include/lldb/Host/Symbols.h b/include/lldb/Host/Symbols.h new file mode 100644 index 000000000..5f8632d22 --- /dev/null +++ b/include/lldb/Host/Symbols.h @@ -0,0 +1,66 @@ +//===-- 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 + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class ArchSpec; +class ModuleSpec; +class UUID; + +class Symbols { +public: + //---------------------------------------------------------------------- + // Locate the executable file given a module specification. + // + // Locating the file should happen only on the local computer or using + // the current computers global settings. + //---------------------------------------------------------------------- + static ModuleSpec LocateExecutableObjectFile(const ModuleSpec &module_spec); + + //---------------------------------------------------------------------- + // Locate the symbol file given a module specification. + // + // Locating the file should happen only on the local computer or using + // the current computers global settings. + //---------------------------------------------------------------------- + static FileSpec LocateExecutableSymbolFile(const ModuleSpec &module_spec); + + static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, + const lldb_private::UUID *uuid, + const ArchSpec *arch); + + //---------------------------------------------------------------------- + // Locate the object and symbol file given a module specification. + // + // Locating the file can try to download the file from a corporate build + // repository, or using any other means necessary to locate both the + // unstripped object file and the debug symbols. + // The force_lookup argument controls whether the external program is called + // unconditionally to find the symbol file, or if the user's settings are + // checked to see if they've enabled the external program before calling. + // + //---------------------------------------------------------------------- + static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + bool force_lookup = true); +}; + +} // namespace lldb_private + +#endif // liblldb_Symbols_h_ diff --git a/include/lldb/Host/Terminal.h b/include/lldb/Host/Terminal.h new file mode 100644 index 000000000..f0d93ad24 --- /dev/null +++ b/include/lldb/Host/Terminal.h @@ -0,0 +1,218 @@ +//===-- Terminal.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Terminal_h_ +#define liblldb_Terminal_h_ +#if defined(__cplusplus) + +#include "lldb/Host/Config.h" +#include "lldb/lldb-private.h" + +struct termios; + +namespace lldb_private { + +class Terminal { +public: + Terminal(int fd = -1) : m_fd(fd) {} + + ~Terminal() {} + + bool IsATerminal() const; + + int GetFileDescriptor() const { return m_fd; } + + void SetFileDescriptor(int fd) { m_fd = fd; } + + bool FileDescriptorIsValid() const { return m_fd != -1; } + + void Clear() { m_fd = -1; } + + bool SetEcho(bool enabled); + + bool SetCanonical(bool enabled); + +protected: + int m_fd; // This may or may not be a terminal file descriptor +}; + +//---------------------------------------------------------------------- +/// @class State Terminal.h "lldb/Host/Terminal.h" +/// @brief A terminal state saving/restoring class. +/// +/// This class can be used to remember the terminal state for a file +/// descriptor and later restore that state as it originally was. +//---------------------------------------------------------------------- +class TerminalState { +public: + //------------------------------------------------------------------ + /// Default constructor + //------------------------------------------------------------------ + TerminalState(); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~TerminalState(); + + //------------------------------------------------------------------ + /// Save the TTY state for \a fd. + /// + /// Save the current state of the TTY for the file descriptor "fd" + /// and if "save_process_group" is true, attempt to save the process + /// group info for the TTY. + /// + /// @param[in] fd + /// The file descriptor to save the state of. + /// + /// @param[in] save_process_group + /// If \b true, save the process group settings, else do not + /// save the process group settings for a TTY. + /// + /// @return + /// Returns \b true if \a fd describes a TTY and if the state + /// was able to be saved, \b false otherwise. + //------------------------------------------------------------------ + bool Save(int fd, bool save_process_group); + + //------------------------------------------------------------------ + /// Restore the TTY state to the cached state. + /// + /// Restore the state of the TTY using the cached values from a + /// previous call to TerminalState::Save(int,bool). + /// + /// @return + /// Returns \b true if the TTY state was successfully restored, + /// \b false otherwise. + //------------------------------------------------------------------ + bool Restore() const; + + //------------------------------------------------------------------ + /// Test for valid cached TTY state information. + /// + /// @return + /// Returns \b true if this object has valid saved TTY state + /// settings that can be used to restore a previous state, + /// \b false otherwise. + //------------------------------------------------------------------ + bool IsValid() const; + + void Clear(); + +protected: + //------------------------------------------------------------------ + /// Test if tflags is valid. + /// + /// @return + /// Returns \b true if \a m_tflags is valid and can be restored, + /// \b false otherwise. + //------------------------------------------------------------------ + bool TFlagsIsValid() const; + + //------------------------------------------------------------------ + /// Test if ttystate is valid. + /// + /// @return + /// Returns \b true if \a m_ttystate is valid and can be + /// restored, \b false otherwise. + //------------------------------------------------------------------ + bool TTYStateIsValid() const; + + //------------------------------------------------------------------ + /// Test if the process group information is valid. + /// + /// @return + /// Returns \b true if \a m_process_group is valid and can be + /// restored, \b false otherwise. + //------------------------------------------------------------------ + bool ProcessGroupIsValid() const; + + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + Terminal m_tty; ///< A terminal + int m_tflags; ///< Cached tflags information. +#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED + std::unique_ptr + m_termios_ap; ///< Cached terminal state information. +#endif + lldb::pid_t m_process_group; ///< Cached process group information. +}; + +//---------------------------------------------------------------------- +/// @class TerminalStateSwitcher Terminal.h "lldb/Host/Terminal.h" +/// @brief A TTY state switching class. +/// +/// This class can be used to remember 2 TTY states for a given file +/// descriptor and switch between the two states. +//---------------------------------------------------------------------- +class TerminalStateSwitcher { +public: + //------------------------------------------------------------------ + /// Constructor + //------------------------------------------------------------------ + TerminalStateSwitcher(); + + //------------------------------------------------------------------ + /// Destructor + //------------------------------------------------------------------ + ~TerminalStateSwitcher(); + + //------------------------------------------------------------------ + /// Get the number of possible states to save. + /// + /// @return + /// The number of states that this TTY switcher object contains. + //------------------------------------------------------------------ + uint32_t GetNumberOfStates() const; + + //------------------------------------------------------------------ + /// Restore the TTY state for state at index \a idx. + /// + /// @return + /// Returns \b true if the TTY state was successfully restored, + /// \b false otherwise. + //------------------------------------------------------------------ + bool Restore(uint32_t idx) const; + + //------------------------------------------------------------------ + /// Save the TTY state information for the state at index \a idx. + /// The TTY state is saved for the file descriptor \a fd and + /// the process group information will also be saved if requested + /// by \a save_process_group. + /// + /// @param[in] idx + /// The index into the state array where the state should be + /// saved. + /// + /// @param[in] fd + /// The file descriptor for which to save the settings. + /// + /// @param[in] save_process_group + /// If \b true, save the process group information for the TTY. + /// + /// @return + /// Returns \b true if the save was successful, \b false + /// otherwise. + //------------------------------------------------------------------ + bool Save(uint32_t idx, int fd, bool save_process_group); + +protected: + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + mutable uint32_t m_currentState; ///< The currently active TTY state index. + TerminalState + m_ttystates[2]; ///< The array of TTY states that holds saved TTY info. +}; + +} // namespace lldb_private + +#endif // #if defined(__cplusplus) +#endif // #ifndef liblldb_Terminal_h_ diff --git a/include/lldb/Host/ThreadLauncher.h b/include/lldb/Host/ThreadLauncher.h new file mode 100644 index 000000000..b50f0e2c2 --- /dev/null +++ b/include/lldb/Host/ThreadLauncher.h @@ -0,0 +1,44 @@ +//===-- ThreadLauncher.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_Host_ThreadLauncher_h_ +#define lldb_Host_ThreadLauncher_h_ + +#include "lldb/Host/HostThread.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-types.h" + +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { + +class ThreadLauncher { +public: + static HostThread + LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_function, + lldb::thread_arg_t thread_arg, Status *error_ptr, + size_t min_stack_byte_size = 0); // Minimum stack size in bytes, + // set stack size to zero for + // default platform thread stack + // size + + struct HostThreadCreateInfo { + std::string thread_name; + lldb::thread_func_t thread_fptr; + lldb::thread_arg_t thread_arg; + + HostThreadCreateInfo(const char *name, lldb::thread_func_t fptr, + lldb::thread_arg_t arg) + : thread_name(name ? name : ""), thread_fptr(fptr), thread_arg(arg) {} + }; +}; +} + +#endif diff --git a/include/lldb/Host/Time.h b/include/lldb/Host/Time.h new file mode 100644 index 000000000..3be30dd03 --- /dev/null +++ b/include/lldb/Host/Time.h @@ -0,0 +1,26 @@ +//===-- Time.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Include system time headers, adding missing functions as necessary + +#ifndef liblldb_Host_Time_h_ +#define liblldb_Host_Time_h_ + +#ifdef __ANDROID__ +#include +#endif + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +#include +extern time_t timegm(struct tm *t); +#else +#include +#endif + +#endif // liblldb_Host_Time_h_ diff --git a/include/lldb/Host/XML.h b/include/lldb/Host/XML.h new file mode 100644 index 000000000..96b522730 --- /dev/null +++ b/include/lldb/Host/XML.h @@ -0,0 +1,191 @@ +//===-- XML.h ---------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_XML_h_ +#define liblldb_XML_h_ + +// C Includes +#if defined(LIBXML2_DEFINED) +#include +#endif + +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +#include "llvm/ADT/StringRef.h" + +// Project includes +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +#if defined(LIBXML2_DEFINED) +typedef xmlNodePtr XMLNodeImpl; +typedef xmlDocPtr XMLDocumentImpl; +#else +typedef void *XMLNodeImpl; +typedef void *XMLDocumentImpl; +#endif + +class XMLNode; + +typedef std::vector NamePath; +typedef std::function NodeCallback; +typedef std::function + AttributeCallback; + +class XMLNode { +public: + XMLNode(); + + XMLNode(XMLNodeImpl node); + + ~XMLNode(); + + explicit operator bool() const { return IsValid(); } + + void Clear(); + + bool IsValid() const; + + bool IsElement() const; + + llvm::StringRef GetName() const; + + bool GetElementText(std::string &text) const; + + bool GetElementTextAsUnsigned(uint64_t &value, uint64_t fail_value = 0, + int base = 0) const; + + bool GetElementTextAsFloat(double &value, double fail_value = 0.0) const; + + bool NameIs(const char *name) const; + + XMLNode GetParent() const; + + XMLNode GetSibling() const; + + XMLNode GetChild() const; + + llvm::StringRef GetAttributeValue(const char *name, + const char *fail_value = nullptr) const; + + XMLNode FindFirstChildElementWithName(const char *name) const; + + XMLNode GetElementForPath(const NamePath &path); + + //---------------------------------------------------------------------- + // Iterate through all sibling nodes of any type + //---------------------------------------------------------------------- + void ForEachSiblingNode(NodeCallback const &callback) const; + + //---------------------------------------------------------------------- + // Iterate through only the sibling nodes that are elements + //---------------------------------------------------------------------- + void ForEachSiblingElement(NodeCallback const &callback) const; + + //---------------------------------------------------------------------- + // Iterate through only the sibling nodes that are elements and whose + // name matches \a name. + //---------------------------------------------------------------------- + void ForEachSiblingElementWithName(const char *name, + NodeCallback const &callback) const; + + void ForEachChildNode(NodeCallback const &callback) const; + + void ForEachChildElement(NodeCallback const &callback) const; + + void ForEachChildElementWithName(const char *name, + NodeCallback const &callback) const; + + void ForEachAttribute(AttributeCallback const &callback) const; + +protected: + XMLNodeImpl m_node; +}; + +class XMLDocument { +public: + XMLDocument(); + + ~XMLDocument(); + + explicit operator bool() const { return IsValid(); } + + bool IsValid() const; + + void Clear(); + + bool ParseFile(const char *path); + + bool ParseMemory(const char *xml, size_t xml_length, + const char *url = "untitled.xml"); + + //---------------------------------------------------------------------- + // If \a name is nullptr, just get the root element node, else only return + // a value XMLNode if the name of the root element matches \a name. + //---------------------------------------------------------------------- + XMLNode GetRootElement(const char *required_name = nullptr); + + llvm::StringRef GetErrors() const; + + static void ErrorCallback(void *ctx, const char *format, ...); + + static bool XMLEnabled(); + +protected: + XMLDocumentImpl m_document; + StreamString m_errors; +}; + +class ApplePropertyList { +public: + ApplePropertyList(); + + ApplePropertyList(const char *path); + + ~ApplePropertyList(); + + bool ParseFile(const char *path); + + llvm::StringRef GetErrors() const; + + explicit operator bool() const { return IsValid(); } + + bool IsValid() const; + + XMLNode GetValueNode(const char *key) const; + + bool GetValueAsString(const char *key, std::string &value) const; + + StructuredData::ObjectSP GetStructuredData(); + +protected: + // Using a node returned from GetValueNode() extract its value as a + // string (if possible). Array and dictionary nodes will return false + // as they have no string value. Boolean nodes will return true and + // \a value will be "true" or "false" as the string value comes from + // the element name itself. All other nodes will return the text + // content of the XMLNode. + static bool ExtractStringFromValueNode(const XMLNode &node, + std::string &value); + + XMLDocument m_xml_doc; + XMLNode m_dict_node; +}; + +} // namespace lldb_private + +#endif // liblldb_XML_h_ diff --git a/include/lldb/Host/android/HostInfoAndroid.h b/include/lldb/Host/android/HostInfoAndroid.h new file mode 100644 index 000000000..7a52abe31 --- /dev/null +++ b/include/lldb/Host/android/HostInfoAndroid.h @@ -0,0 +1,33 @@ +//===-- HostInfoAndroid.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_Host_android_HostInfoAndroid_h_ +#define lldb_Host_android_HostInfoAndroid_h_ + +#include "lldb/Host/linux/HostInfoLinux.h" + +namespace lldb_private { + +class HostInfoAndroid : public HostInfoLinux { + friend class HostInfoBase; + +public: + static FileSpec GetDefaultShell(); + static FileSpec ResolveLibraryPath(const std::string &path, + const ArchSpec &arch); + +protected: + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); + static bool ComputeTempFileBaseDirectory(FileSpec &file_spec); +}; + +} // end of namespace lldb_private + +#endif // #ifndef lldb_Host_android_HostInfoAndroid_h_ diff --git a/include/lldb/Host/common/GetOptInc.h b/include/lldb/Host/common/GetOptInc.h new file mode 100644 index 000000000..4d5cab5cb --- /dev/null +++ b/include/lldb/Host/common/GetOptInc.h @@ -0,0 +1,52 @@ +#pragma once + +#include "lldb/lldb-defines.h" + +#if defined(_MSC_VER) +#define REPLACE_GETOPT +#define REPLACE_GETOPT_LONG +#endif +#if defined(_MSC_VER) || defined(__NetBSD__) +#define REPLACE_GETOPT_LONG_ONLY +#endif + +#if defined(REPLACE_GETOPT) +// from getopt.h +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +// option structure +struct option { + const char *name; + // has_arg can't be an enum because some compilers complain about + // type mismatches in all the code that assumes it is an int. + int has_arg; + int *flag; + int val; +}; + +int getopt(int argc, char *const argv[], const char *optstring); + +// from getopt.h +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +// defined in unistd.h +extern int optreset; +#else +#include +#include +#endif + +#if defined(REPLACE_GETOPT_LONG) +int getopt_long(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longindex); +#endif + +#if defined(REPLACE_GETOPT_LONG_ONLY) +int getopt_long_only(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longindex); +#endif diff --git a/include/lldb/Host/common/NativeBreakpoint.h b/include/lldb/Host/common/NativeBreakpoint.h new file mode 100644 index 000000000..73639d64c --- /dev/null +++ b/include/lldb/Host/common/NativeBreakpoint.h @@ -0,0 +1,56 @@ +//===-- NativeBreakpoint.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeBreakpoint_h_ +#define liblldb_NativeBreakpoint_h_ + +#include "lldb/lldb-types.h" + +namespace lldb_private { +class NativeBreakpointList; + +class NativeBreakpoint { + friend class NativeBreakpointList; + +public: + // The assumption is that derived breakpoints are enabled when created. + NativeBreakpoint(lldb::addr_t addr); + + virtual ~NativeBreakpoint(); + + Status Enable(); + + Status Disable(); + + lldb::addr_t GetAddress() const { return m_addr; } + + bool IsEnabled() const { return m_enabled; } + + virtual bool IsSoftwareBreakpoint() const = 0; + +protected: + const lldb::addr_t m_addr; + int32_t m_ref_count; + + virtual Status DoEnable() = 0; + + virtual Status DoDisable() = 0; + +private: + bool m_enabled; + + // ----------------------------------------------------------- + // interface for NativeBreakpointList + // ----------------------------------------------------------- + void AddRef(); + int32_t DecRef(); +}; +} + +#endif // ifndef liblldb_NativeBreakpoint_h_ diff --git a/include/lldb/Host/common/NativeBreakpointList.h b/include/lldb/Host/common/NativeBreakpointList.h new file mode 100644 index 000000000..ffa659fdd --- /dev/null +++ b/include/lldb/Host/common/NativeBreakpointList.h @@ -0,0 +1,60 @@ +//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeBreakpointList_h_ +#define liblldb_NativeBreakpointList_h_ + +#include "lldb/Utility/Status.h" +#include "lldb/lldb-private-forward.h" +// #include "lldb/Host/NativeBreakpoint.h" + +#include +#include +#include + +namespace lldb_private { + +struct HardwareBreakpoint { + lldb::addr_t m_addr; + size_t m_size; +}; + +using HardwareBreakpointMap = std::map; + +class NativeBreakpointList { +public: + typedef std::function + CreateBreakpointFunc; + + NativeBreakpointList(); + + Status AddRef(lldb::addr_t addr, size_t size_hint, bool hardware, + CreateBreakpointFunc create_func); + + Status DecRef(lldb::addr_t addr); + + Status EnableBreakpoint(lldb::addr_t addr); + + Status DisableBreakpoint(lldb::addr_t addr); + + Status GetBreakpoint(lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp); + + Status RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf, size_t size) const; + +private: + typedef std::map BreakpointMap; + + std::recursive_mutex m_mutex; + BreakpointMap m_breakpoints; +}; +} + +#endif // ifndef liblldb_NativeBreakpointList_h_ diff --git a/include/lldb/Host/common/NativeProcessProtocol.h b/include/lldb/Host/common/NativeProcessProtocol.h new file mode 100644 index 000000000..9671d710f --- /dev/null +++ b/include/lldb/Host/common/NativeProcessProtocol.h @@ -0,0 +1,476 @@ +//===-- NativeProcessProtocol.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeProcessProtocol_h_ +#define liblldb_NativeProcessProtocol_h_ + +#include "lldb/Host/Host.h" +#include "lldb/Host/MainLoop.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/TraceOptions.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +#include "NativeBreakpointList.h" +#include "NativeWatchpointList.h" + +namespace lldb_private { +class MemoryRegionInfo; +class ResumeActionList; + +//------------------------------------------------------------------ +// NativeProcessProtocol +//------------------------------------------------------------------ +class NativeProcessProtocol { + friend class SoftwareBreakpoint; + +public: + virtual ~NativeProcessProtocol() {} + + virtual Status Resume(const ResumeActionList &resume_actions) = 0; + + virtual Status Halt() = 0; + + virtual Status Detach() = 0; + + //------------------------------------------------------------------ + /// Sends a process a UNIX signal \a signal. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Status Signal(int signo) = 0; + + //------------------------------------------------------------------ + /// Tells a process to interrupt all operations as if by a Ctrl-C. + /// + /// The default implementation will send a local host's equivalent of + /// a SIGSTOP to the process via the NativeProcessProtocol::Signal() + /// operation. + /// + /// @return + /// Returns an error object. + //------------------------------------------------------------------ + virtual Status Interrupt(); + + virtual Status Kill() = 0; + + //------------------------------------------------------------------ + // Tells a process not to stop the inferior on given signals + // and just reinject them back. + //------------------------------------------------------------------ + virtual Status IgnoreSignals(llvm::ArrayRef signals); + + //---------------------------------------------------------------------- + // Memory and memory region functions + //---------------------------------------------------------------------- + + virtual Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info); + + virtual Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) = 0; + + virtual Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, + size_t size, size_t &bytes_read) = 0; + + virtual Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) = 0; + + virtual Status AllocateMemory(size_t size, uint32_t permissions, + lldb::addr_t &addr) = 0; + + virtual Status DeallocateMemory(lldb::addr_t addr) = 0; + + virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0; + + virtual bool IsAlive() const; + + virtual size_t UpdateThreads() = 0; + + virtual bool GetArchitecture(ArchSpec &arch) const = 0; + + //---------------------------------------------------------------------- + // Breakpoint functions + //---------------------------------------------------------------------- + virtual Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) = 0; + + virtual Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false); + + virtual Status EnableBreakpoint(lldb::addr_t addr); + + virtual Status DisableBreakpoint(lldb::addr_t addr); + + //---------------------------------------------------------------------- + // Hardware Breakpoint functions + //---------------------------------------------------------------------- + virtual const HardwareBreakpointMap &GetHardwareBreakpointMap() const; + + virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size); + + virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr); + + //---------------------------------------------------------------------- + // Watchpoint functions + //---------------------------------------------------------------------- + virtual const NativeWatchpointList::WatchpointMap &GetWatchpointMap() const; + + virtual llvm::Optional> + GetHardwareDebugSupportInfo() const; + + virtual Status SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware); + + virtual Status RemoveWatchpoint(lldb::addr_t addr); + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + lldb::pid_t GetID() const { return m_pid; } + + lldb::StateType GetState() const; + + bool IsRunning() const { + return m_state == lldb::eStateRunning || IsStepping(); + } + + bool IsStepping() const { return m_state == lldb::eStateStepping; } + + bool CanResume() const { return m_state == lldb::eStateStopped; } + + bool GetByteOrder(lldb::ByteOrder &byte_order) const; + + virtual llvm::ErrorOr> + GetAuxvData() const = 0; + + //---------------------------------------------------------------------- + // Exit Status + //---------------------------------------------------------------------- + virtual llvm::Optional GetExitStatus(); + + virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange); + + //---------------------------------------------------------------------- + // Access to threads + //---------------------------------------------------------------------- + NativeThreadProtocolSP GetThreadAtIndex(uint32_t idx); + + NativeThreadProtocolSP GetThreadByID(lldb::tid_t tid); + + void SetCurrentThreadID(lldb::tid_t tid) { m_current_thread_id = tid; } + + lldb::tid_t GetCurrentThreadID() { return m_current_thread_id; } + + NativeThreadProtocolSP GetCurrentThread() { + return GetThreadByID(m_current_thread_id); + } + + //---------------------------------------------------------------------- + // Access to inferior stdio + //---------------------------------------------------------------------- + virtual int GetTerminalFileDescriptor() { return m_terminal_fd; } + + //---------------------------------------------------------------------- + // Stop id interface + //---------------------------------------------------------------------- + + uint32_t GetStopID() const; + + // --------------------------------------------------------------------- + // Callbacks for low-level process state changes + // --------------------------------------------------------------------- + class NativeDelegate { + public: + virtual ~NativeDelegate() {} + + virtual void InitializeDelegate(NativeProcessProtocol *process) = 0; + + virtual void ProcessStateChanged(NativeProcessProtocol *process, + lldb::StateType state) = 0; + + virtual void DidExec(NativeProcessProtocol *process) = 0; + }; + + //------------------------------------------------------------------ + /// Register a native delegate. + /// + /// Clients can register nofication callbacks by passing in a + /// NativeDelegate impl and passing it into this function. + /// + /// Note: it is required that the lifetime of the + /// native_delegate outlive the NativeProcessProtocol. + /// + /// @param[in] native_delegate + /// A NativeDelegate impl to be called when certain events + /// happen within the NativeProcessProtocol or related threads. + /// + /// @return + /// true if the delegate was registered successfully; + /// false if the delegate was already registered. + /// + /// @see NativeProcessProtocol::NativeDelegate. + //------------------------------------------------------------------ + bool RegisterNativeDelegate(NativeDelegate &native_delegate); + + //------------------------------------------------------------------ + /// Unregister a native delegate previously registered. + /// + /// @param[in] native_delegate + /// A NativeDelegate impl previously registered with this process. + /// + /// @return Returns \b true if the NativeDelegate was + /// successfully removed from the process, \b false otherwise. + /// + /// @see NativeProcessProtocol::NativeDelegate + //------------------------------------------------------------------ + bool UnregisterNativeDelegate(NativeDelegate &native_delegate); + + virtual Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) = 0; + + virtual Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) = 0; + + class Factory { + public: + virtual ~Factory(); + //------------------------------------------------------------------ + /// Launch a process for debugging. + /// + /// @param[in] launch_info + /// Information required to launch the process. + /// + /// @param[in] native_delegate + /// The delegate that will receive messages regarding the + /// inferior. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @param[in] mainloop + /// The mainloop instance with which the process can register + /// callbacks. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @return + /// A NativeProcessProtocol shared pointer if the operation succeeded or + /// an error object if it failed. + //------------------------------------------------------------------ + virtual llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop) const = 0; + + //------------------------------------------------------------------ + /// Attach to an existing process. + /// + /// @param[in] pid + /// pid of the process locatable + /// + /// @param[in] native_delegate + /// The delegate that will receive messages regarding the + /// inferior. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @param[in] mainloop + /// The mainloop instance with which the process can register + /// callbacks. Must outlive the NativeProcessProtocol + /// instance. + /// + /// @return + /// A NativeProcessProtocol shared pointer if the operation succeeded or + /// an error object if it failed. + //------------------------------------------------------------------ + virtual llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop) const = 0; + }; + + //------------------------------------------------------------------ + /// StartTracing API for starting a tracing instance with the + /// TraceOptions on a specific thread or process. + /// + /// @param[in] config + /// The configuration to use when starting tracing. + /// + /// @param[out] error + /// Status indicates what went wrong. + /// + /// @return + /// The API returns a user_id which can be used to get trace + /// data, trace configuration or stopping the trace instance. + /// The user_id is a key to identify and operate with a tracing + /// instance. It may refer to the complete process or a single + /// thread. + //------------------------------------------------------------------ + virtual lldb::user_id_t StartTrace(const TraceOptions &config, + Status &error) { + error.SetErrorString("Not implemented"); + return LLDB_INVALID_UID; + } + + //------------------------------------------------------------------ + /// StopTracing API as the name suggests stops a tracing instance. + /// + /// @param[in] traceid + /// The user id of the trace intended to be stopped. Now a + /// user_id may map to multiple threads in which case this API + /// could be used to stop the tracing for a specific thread by + /// supplying its thread id. + /// + /// @param[in] thread + /// Thread is needed when the complete process is being traced + /// and the user wishes to stop tracing on a particular thread. + /// + /// @return + /// Status indicating what went wrong. + //------------------------------------------------------------------ + virtual Status StopTrace(lldb::user_id_t traceid, + lldb::tid_t thread = LLDB_INVALID_THREAD_ID) { + return Status("Not implemented"); + } + + //------------------------------------------------------------------ + /// This API provides the trace data collected in the form of raw + /// data. + /// + /// @param[in] traceid thread + /// The traceid and thread provide the context for the trace + /// instance. + /// + /// @param[in] buffer + /// The buffer provides the destination buffer where the trace + /// data would be read to. The buffer should be truncated to the + /// filled length by this function. + /// + /// @param[in] offset + /// There is possibility to read partially the trace data from + /// a specified offset where in such cases the buffer provided + /// may be smaller than the internal trace collection container. + /// + /// @return + /// The size of the data actually read. + //------------------------------------------------------------------ + virtual Status GetData(lldb::user_id_t traceid, lldb::tid_t thread, + llvm::MutableArrayRef &buffer, + size_t offset = 0) { + return Status("Not implemented"); + } + + //------------------------------------------------------------------ + /// Similar API as above except it aims to provide any extra data + /// useful for decoding the actual trace data. + //------------------------------------------------------------------ + virtual Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread, + llvm::MutableArrayRef &buffer, + size_t offset = 0) { + return Status("Not implemented"); + } + + //------------------------------------------------------------------ + /// API to query the TraceOptions for a given user id + /// + /// @param[in] traceid + /// The user id of the tracing instance. + /// + /// @param[in] config + /// The thread id of the tracing instance, in case configuration + /// for a specific thread is needed should be specified in the + /// config. + /// + /// @param[out] error + /// Status indicates what went wrong. + /// + /// @param[out] config + /// The actual configuration being used for tracing. + //------------------------------------------------------------------ + virtual Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) { + return Status("Not implemented"); + } + +protected: + lldb::pid_t m_pid; + + std::vector m_threads; + lldb::tid_t m_current_thread_id = LLDB_INVALID_THREAD_ID; + mutable std::recursive_mutex m_threads_mutex; + + lldb::StateType m_state = lldb::eStateInvalid; + mutable std::recursive_mutex m_state_mutex; + + llvm::Optional m_exit_status; + + std::recursive_mutex m_delegates_mutex; + std::vector m_delegates; + NativeBreakpointList m_breakpoint_list; + NativeWatchpointList m_watchpoint_list; + HardwareBreakpointMap m_hw_breakpoints_map; + int m_terminal_fd; + uint32_t m_stop_id = 0; + + // Set of signal numbers that LLDB directly injects back to inferior + // without stopping it. + llvm::DenseSet m_signals_to_ignore; + + // lldb_private::Host calls should be used to launch a process for debugging, + // and + // then the process should be attached to. When attaching to a process + // lldb_private::Host calls should be used to locate the process to attach to, + // and then this function should be called. + NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, + NativeDelegate &delegate); + + // ----------------------------------------------------------- + // Internal interface for state handling + // ----------------------------------------------------------- + void SetState(lldb::StateType state, bool notify_delegates = true); + + // Derived classes need not implement this. It can be used as a + // hook to clear internal caches that should be invalidated when + // stop ids change. + // + // Note this function is called with the state mutex obtained + // by the caller. + virtual void DoStopIDBumped(uint32_t newBumpId); + + // ----------------------------------------------------------- + // Internal interface for software breakpoints + // ----------------------------------------------------------- + Status SetSoftwareBreakpoint(lldb::addr_t addr, uint32_t size_hint); + + virtual Status + GetSoftwareBreakpointTrapOpcode(size_t trap_opcode_size_hint, + size_t &actual_opcode_size, + const uint8_t *&trap_opcode_bytes) = 0; + + // ----------------------------------------------------------- + /// Notify the delegate that an exec occurred. + /// + /// Provide a mechanism for a delegate to clear out any exec- + /// sensitive data. + // ----------------------------------------------------------- + void NotifyDidExec(); + + NativeThreadProtocolSP GetThreadByIDUnlocked(lldb::tid_t tid); + + // ----------------------------------------------------------- + // Static helper methods for derived classes. + // ----------------------------------------------------------- + static Status ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch); + +private: + void SynchronouslyNotifyProcessStateChanged(lldb::StateType state); +}; +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessProtocol_h_ diff --git a/include/lldb/Host/common/NativeRegisterContext.h b/include/lldb/Host/common/NativeRegisterContext.h new file mode 100644 index 000000000..982d81b9a --- /dev/null +++ b/include/lldb/Host/common/NativeRegisterContext.h @@ -0,0 +1,201 @@ +//===-- NativeRegisterContext.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeRegisterContext_h_ +#define liblldb_NativeRegisterContext_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Host/common/NativeWatchpointList.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class NativeThreadProtocol; + +class NativeRegisterContext + : public std::enable_shared_from_this { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + NativeRegisterContext(NativeThreadProtocol &thread, + uint32_t concrete_frame_idx); + + virtual ~NativeRegisterContext(); + + // void + // InvalidateIfNeeded (bool force); + + //------------------------------------------------------------------ + // Subclasses must override these functions + //------------------------------------------------------------------ + // virtual void + // InvalidateAllRegisters () = 0; + + virtual uint32_t GetRegisterCount() const = 0; + + virtual uint32_t GetUserRegisterCount() const = 0; + + virtual const RegisterInfo *GetRegisterInfoAtIndex(uint32_t reg) const = 0; + + const char *GetRegisterSetNameForRegisterAtIndex(uint32_t reg_index) const; + + virtual uint32_t GetRegisterSetCount() const = 0; + + virtual const RegisterSet *GetRegisterSet(uint32_t set_index) const = 0; + + virtual Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) = 0; + + virtual Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) = 0; + + virtual Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) = 0; + + virtual Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) = 0; + + uint32_t ConvertRegisterKindToRegisterNumber(uint32_t kind, + uint32_t num) const; + + //------------------------------------------------------------------ + // 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 Status ClearAllHardwareBreakpoints(); + + virtual Status GetHardwareBreakHitIndex(uint32_t &bp_index, + lldb::addr_t trap_addr); + + virtual uint32_t NumSupportedHardwareWatchpoints(); + + virtual uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags); + + virtual bool ClearHardwareWatchpoint(uint32_t hw_index); + + virtual Status ClearAllHardwareWatchpoints(); + + virtual Status IsWatchpointHit(uint32_t wp_index, bool &is_hit); + + virtual Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr); + + virtual Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant); + + virtual lldb::addr_t GetWatchpointAddress(uint32_t wp_index); + + // MIPS Linux kernel returns a masked address (last 3bits are masked) + // when a HW watchpoint is hit. However user may not have set a watchpoint + // on this address. This function emulates the instruction at PC and + // finds the base address used in the load/store instruction. This gives the + // exact address used to read/write the variable being watched. + // For example: + // 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at + // 'm', + // then watch exception is generated even when 'n' is read/written. This + // function + // returns address of 'n' so that client can check whether a watchpoint is set + // on this address or not. + virtual lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index); + + virtual bool HardwareSingleStep(bool enable); + + virtual Status + ReadRegisterValueFromMemory(const lldb_private::RegisterInfo *reg_info, + lldb::addr_t src_addr, size_t src_len, + RegisterValue ®_value); + + virtual Status + WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info, + lldb::addr_t dst_addr, size_t dst_len, + const RegisterValue ®_value); + + //------------------------------------------------------------------ + // Subclasses should not override these + //------------------------------------------------------------------ + virtual lldb::tid_t GetThreadID() const; + + virtual NativeThreadProtocol &GetThread() { return m_thread; } + + const RegisterInfo *GetRegisterInfoByName(llvm::StringRef reg_name, + uint32_t start_idx = 0); + + const RegisterInfo *GetRegisterInfo(uint32_t reg_kind, uint32_t reg_num); + + lldb::addr_t GetPC(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS); + + virtual lldb::addr_t + GetPCfromBreakpointLocation(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS); + + Status SetPC(lldb::addr_t pc); + + lldb::addr_t GetSP(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS); + + Status SetSP(lldb::addr_t sp); + + lldb::addr_t GetFP(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS); + + Status SetFP(lldb::addr_t fp); + + const char *GetRegisterName(uint32_t reg); + + lldb::addr_t GetReturnAddress(lldb::addr_t fail_value = LLDB_INVALID_ADDRESS); + + lldb::addr_t GetFlags(lldb::addr_t fail_value = 0); + + lldb::addr_t ReadRegisterAsUnsigned(uint32_t reg, lldb::addr_t fail_value); + + lldb::addr_t ReadRegisterAsUnsigned(const RegisterInfo *reg_info, + lldb::addr_t fail_value); + + Status WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval); + + Status WriteRegisterFromUnsigned(const RegisterInfo *reg_info, uint64_t uval); + + // uint32_t + // GetStopID () const + // { + // return m_stop_id; + // } + + // void + // SetStopID (uint32_t stop_id) + // { + // m_stop_id = stop_id; + // } + +protected: + //------------------------------------------------------------------ + // Classes that inherit from RegisterContext can see and modify these + //------------------------------------------------------------------ + NativeThreadProtocol + &m_thread; // The thread that this register context belongs to. + uint32_t m_concrete_frame_idx; // The concrete frame index for this register + // context + // uint32_t m_stop_id; // The stop ID that any data in this + // context is valid for + +private: + //------------------------------------------------------------------ + // For RegisterContext only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN(NativeRegisterContext); +}; + +} // namespace lldb_private + +#endif // liblldb_NativeRegisterContext_h_ diff --git a/include/lldb/Host/common/NativeThreadProtocol.h b/include/lldb/Host/common/NativeThreadProtocol.h new file mode 100644 index 000000000..d96f71311 --- /dev/null +++ b/include/lldb/Host/common/NativeThreadProtocol.h @@ -0,0 +1,72 @@ +//===-- NativeThreadProtocol.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeThreadProtocol_h_ +#define liblldb_NativeThreadProtocol_h_ + +#include + +#include "lldb/Host/Debug.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { +//------------------------------------------------------------------ +// NativeThreadProtocol +//------------------------------------------------------------------ +class NativeThreadProtocol + : public std::enable_shared_from_this { +public: + NativeThreadProtocol(NativeProcessProtocol &process, lldb::tid_t tid); + + virtual ~NativeThreadProtocol() {} + + virtual std::string GetName() = 0; + + virtual lldb::StateType GetState() = 0; + + virtual NativeRegisterContextSP GetRegisterContext() = 0; + + virtual Status ReadRegister(uint32_t reg, RegisterValue ®_value); + + virtual Status WriteRegister(uint32_t reg, const RegisterValue ®_value); + + virtual Status SaveAllRegisters(lldb::DataBufferSP &data_sp); + + virtual Status RestoreAllRegisters(lldb::DataBufferSP &data_sp); + + virtual bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) = 0; + + lldb::tid_t GetID() const { return m_tid; } + + NativeProcessProtocol &GetProcess() { return m_process; } + + // --------------------------------------------------------------------- + // Thread-specific watchpoints + // --------------------------------------------------------------------- + virtual Status SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) = 0; + + virtual Status RemoveWatchpoint(lldb::addr_t addr) = 0; + + // --------------------------------------------------------------------- + // Thread-specific Hardware Breakpoint routines + // --------------------------------------------------------------------- + virtual Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) = 0; + + virtual Status RemoveHardwareBreakpoint(lldb::addr_t addr) = 0; + +protected: + NativeProcessProtocol &m_process; + lldb::tid_t m_tid; +}; +} + +#endif // #ifndef liblldb_NativeThreadProtocol_h_ diff --git a/include/lldb/Host/common/NativeWatchpointList.h b/include/lldb/Host/common/NativeWatchpointList.h new file mode 100644 index 000000000..02920e6fa --- /dev/null +++ b/include/lldb/Host/common/NativeWatchpointList.h @@ -0,0 +1,42 @@ +//===-- NativeWatchpointList.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_NativeWatchpointList_h_ +#define liblldb_NativeWatchpointList_h_ + +#include "lldb/Utility/Status.h" +#include "lldb/lldb-private-forward.h" + +#include + +namespace lldb_private { +struct NativeWatchpoint { + lldb::addr_t m_addr; + size_t m_size; + uint32_t m_watch_flags; + bool m_hardware; +}; + +class NativeWatchpointList { +public: + Status Add(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware); + + Status Remove(lldb::addr_t addr); + + using WatchpointMap = std::map; + + const WatchpointMap &GetWatchpointMap() const; + +private: + WatchpointMap m_watchpoints; +}; +} + +#endif // ifndef liblldb_NativeWatchpointList_h_ diff --git a/include/lldb/Host/common/SoftwareBreakpoint.h b/include/lldb/Host/common/SoftwareBreakpoint.h new file mode 100644 index 000000000..e0f235fec --- /dev/null +++ b/include/lldb/Host/common/SoftwareBreakpoint.h @@ -0,0 +1,53 @@ +//===-- SoftwareBreakpoint.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_SoftwareBreakpoint_h_ +#define liblldb_SoftwareBreakpoint_h_ + +#include "NativeBreakpoint.h" +#include "lldb/lldb-private-forward.h" + +namespace lldb_private { +class SoftwareBreakpoint : public NativeBreakpoint { + friend class NativeBreakpointList; + +public: + static Status CreateSoftwareBreakpoint(NativeProcessProtocol &process, + lldb::addr_t addr, size_t size_hint, + NativeBreakpointSP &breakpoint_spn); + + SoftwareBreakpoint(NativeProcessProtocol &process, lldb::addr_t addr, + const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, + size_t opcode_size); + +protected: + Status DoEnable() override; + + Status DoDisable() override; + + bool IsSoftwareBreakpoint() const override; + +private: + /// Max number of bytes that a software trap opcode sequence can occupy. + static const size_t MAX_TRAP_OPCODE_SIZE = 8; + + NativeProcessProtocol &m_process; + uint8_t m_saved_opcodes[MAX_TRAP_OPCODE_SIZE]; + uint8_t m_trap_opcodes[MAX_TRAP_OPCODE_SIZE]; + const size_t m_opcode_size; + + static Status EnableSoftwareBreakpoint(NativeProcessProtocol &process, + lldb::addr_t addr, + size_t bp_opcode_size, + const uint8_t *bp_opcode_bytes, + uint8_t *saved_opcode_bytes); +}; +} + +#endif // #ifndef liblldb_SoftwareBreakpoint_h_ diff --git a/include/lldb/Host/common/TCPSocket.h b/include/lldb/Host/common/TCPSocket.h new file mode 100644 index 000000000..0d32a70fd --- /dev/null +++ b/include/lldb/Host/common/TCPSocket.h @@ -0,0 +1,59 @@ +//===-- TCPSocket.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_TCPSocket_h_ +#define liblldb_TCPSocket_h_ + +#include "lldb/Host/Socket.h" +#include "lldb/Host/SocketAddress.h" +#include + +namespace lldb_private { +class TCPSocket : public Socket { +public: + TCPSocket(bool should_close, bool child_processes_inherit); + TCPSocket(NativeSocket socket, bool should_close, + bool child_processes_inherit); + ~TCPSocket() override; + + // returns port number or 0 if error + uint16_t GetLocalPortNumber() const; + + // returns ip address string or empty string if error + std::string GetLocalIPAddress() const; + + // must be connected + // returns port number or 0 if error + uint16_t GetRemotePortNumber() const; + + // must be connected + // returns ip address string or empty string if error + std::string GetRemoteIPAddress() const; + + int SetOptionNoDelay(); + int SetOptionReuseAddress(); + + Status Connect(llvm::StringRef name) override; + Status Listen(llvm::StringRef name, int backlog) override; + Status Accept(Socket *&conn_socket) override; + + Status CreateSocket(int domain); + + bool IsValid() const override; + +private: + TCPSocket(NativeSocket socket, const TCPSocket &listen_socket); + + void CloseListenSockets(); + + std::map m_listen_sockets; +}; +} + +#endif // ifndef liblldb_TCPSocket_h_ diff --git a/include/lldb/Host/common/UDPSocket.h b/include/lldb/Host/common/UDPSocket.h new file mode 100644 index 000000000..27b2d1dc9 --- /dev/null +++ b/include/lldb/Host/common/UDPSocket.h @@ -0,0 +1,35 @@ +//===-- UDPSocket.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UDPSocket_h_ +#define liblldb_UDPSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private { +class UDPSocket : public Socket { +public: + UDPSocket(bool should_close, bool child_processes_inherit); + + static Status Connect(llvm::StringRef name, bool child_processes_inherit, + Socket *&socket); + +private: + UDPSocket(NativeSocket socket); + + size_t Send(const void *buf, const size_t num_bytes) override; + Status Connect(llvm::StringRef name) override; + Status Listen(llvm::StringRef name, int backlog) override; + Status Accept(Socket *&socket) override; + + SocketAddress m_sockaddr; +}; +} + +#endif // ifndef liblldb_UDPSocket_h_ diff --git a/include/lldb/Host/freebsd/HostInfoFreeBSD.h b/include/lldb/Host/freebsd/HostInfoFreeBSD.h new file mode 100644 index 000000000..945ec835f --- /dev/null +++ b/include/lldb/Host/freebsd/HostInfoFreeBSD.h @@ -0,0 +1,27 @@ +//===-- HostInfoFreeBSD.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_Host_freebsd_HostInfoFreeBSD_h_ +#define lldb_Host_freebsd_HostInfoFreeBSD_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class HostInfoFreeBSD : public HostInfoPosix { +public: + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static FileSpec GetProgramFileSpec(); +}; +} + +#endif diff --git a/include/lldb/Host/linux/AbstractSocket.h b/include/lldb/Host/linux/AbstractSocket.h new file mode 100644 index 000000000..3b38cde05 --- /dev/null +++ b/include/lldb/Host/linux/AbstractSocket.h @@ -0,0 +1,26 @@ +//===-- AbstractSocket.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AbstractSocket_h_ +#define liblldb_AbstractSocket_h_ + +#include "lldb/Host/posix/DomainSocket.h" + +namespace lldb_private { +class AbstractSocket : public DomainSocket { +public: + AbstractSocket(bool child_processes_inherit); + +protected: + size_t GetNameOffset() const override; + void DeleteSocketFile(llvm::StringRef name) override; +}; +} + +#endif // ifndef liblldb_AbstractSocket_h_ diff --git a/include/lldb/Host/linux/HostInfoLinux.h b/include/lldb/Host/linux/HostInfoLinux.h new file mode 100644 index 000000000..d1f2e747b --- /dev/null +++ b/include/lldb/Host/linux/HostInfoLinux.h @@ -0,0 +1,48 @@ +//===-- HostInfoLinux.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_Host_linux_HostInfoLinux_h_ +#define lldb_Host_linux_HostInfoLinux_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" + +#include "llvm/ADT/StringRef.h" + +#include + +namespace lldb_private { + +class HostInfoLinux : public HostInfoPosix { + friend class HostInfoBase; + +private: + // Static class, unconstructable. + HostInfoLinux(); + ~HostInfoLinux(); + +public: + static void Initialize(); + + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static llvm::StringRef GetDistributionId(); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); +}; +} + +#endif diff --git a/include/lldb/Host/linux/Ptrace.h b/include/lldb/Host/linux/Ptrace.h new file mode 100644 index 000000000..1b753c284 --- /dev/null +++ b/include/lldb/Host/linux/Ptrace.h @@ -0,0 +1,57 @@ +//===-- Ptrace.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This file defines ptrace functions & structures + +#ifndef liblldb_Host_linux_Ptrace_h_ +#define liblldb_Host_linux_Ptrace_h_ + +#include + +#ifndef __GLIBC__ +typedef int __ptrace_request; +#endif + +#define DEBUG_PTRACE_MAXBYTES 20 + +// Support ptrace extensions even when compiled without required kernel support +#ifndef PTRACE_GETREGS +#define PTRACE_GETREGS 12 +#endif +#ifndef PTRACE_SETREGS +#define PTRACE_SETREGS 13 +#endif +#ifndef PTRACE_GETFPREGS +#define PTRACE_GETFPREGS 14 +#endif +#ifndef PTRACE_SETFPREGS +#define PTRACE_SETFPREGS 15 +#endif +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif +#ifndef PTRACE_ARCH_PRCTL +#define PTRACE_ARCH_PRCTL 30 +#endif +#ifndef ARCH_GET_FS +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#endif + +#define LLDB_PTRACE_NT_ARM_TLS 0x401 // ARM TLS register + +#endif // liblldb_Host_linux_Ptrace_h_ diff --git a/include/lldb/Host/linux/Support.h b/include/lldb/Host/linux/Support.h new file mode 100644 index 000000000..8415aa6c4 --- /dev/null +++ b/include/lldb/Host/linux/Support.h @@ -0,0 +1,30 @@ +//===-- Support.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_HOST_LINUX_SUPPORT_H +#define LLDB_HOST_LINUX_SUPPORT_H + +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include + +namespace lldb_private { + +llvm::ErrorOr> +getProcFile(::pid_t pid, ::pid_t tid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(::pid_t pid, const llvm::Twine &file); + +llvm::ErrorOr> +getProcFile(const llvm::Twine &file); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_LINUX_SUPPORT_H diff --git a/include/lldb/Host/linux/Uio.h b/include/lldb/Host/linux/Uio.h new file mode 100644 index 000000000..0b8b7dbf6 --- /dev/null +++ b/include/lldb/Host/linux/Uio.h @@ -0,0 +1,24 @@ +//===-- Uio.h ---------------------------------------------------*- 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_linux_Uio_h_ +#define liblldb_Host_linux_Uio_h_ + +#include "lldb/Host/Config.h" +#include + +// We shall provide our own implementation of process_vm_readv if it is not +// present +#if !HAVE_PROCESS_VM_READV +ssize_t process_vm_readv(::pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags); +#endif + +#endif // liblldb_Host_linux_Uio_h_ diff --git a/include/lldb/Host/macosx/HostInfoMacOSX.h b/include/lldb/Host/macosx/HostInfoMacOSX.h new file mode 100644 index 000000000..eee842bee --- /dev/null +++ b/include/lldb/Host/macosx/HostInfoMacOSX.h @@ -0,0 +1,46 @@ +//===-- HostInfoMacOSX.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_Host_macosx_HostInfoMacOSX_h_ +#define lldb_Host_macosx_HostInfoMacOSX_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class ArchSpec; + +class HostInfoMacOSX : public HostInfoPosix { + friend class HostInfoBase; + +private: + // Static class, unconstructable. + HostInfoMacOSX(); + ~HostInfoMacOSX(); + +public: + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static FileSpec GetProgramFileSpec(); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static void ComputeHostArchitectureSupport(ArchSpec &arch_32, + ArchSpec &arch_64); + static bool ComputeHeaderDirectory(FileSpec &file_spec); + static bool ComputePythonDirectory(FileSpec &file_spec); + static bool ComputeClangDirectory(FileSpec &file_spec); + static bool ComputeSystemPluginsDirectory(FileSpec &file_spec); + static bool ComputeUserPluginsDirectory(FileSpec &file_spec); +}; +} + +#endif diff --git a/include/lldb/Host/macosx/HostThreadMacOSX.h b/include/lldb/Host/macosx/HostThreadMacOSX.h new file mode 100644 index 000000000..16b9a6d69 --- /dev/null +++ b/include/lldb/Host/macosx/HostThreadMacOSX.h @@ -0,0 +1,29 @@ +//===-- HostThreadMacOSX.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_Host_macosx_HostThreadMacOSX_h_ +#define lldb_Host_macosx_HostThreadMacOSX_h_ + +#include "lldb/Host/posix/HostThreadPosix.h" + +namespace lldb_private { + +class HostThreadMacOSX : public HostThreadPosix { + friend class ThreadLauncher; + +public: + HostThreadMacOSX(); + HostThreadMacOSX(lldb::thread_t thread); + +protected: + static lldb::thread_result_t ThreadCreateTrampoline(lldb::thread_arg_t arg); +}; +} + +#endif diff --git a/include/lldb/Host/netbsd/HostInfoNetBSD.h b/include/lldb/Host/netbsd/HostInfoNetBSD.h new file mode 100644 index 000000000..9ebff6ba6 --- /dev/null +++ b/include/lldb/Host/netbsd/HostInfoNetBSD.h @@ -0,0 +1,27 @@ +//===-- HostInfoNetBSD.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_Host_netbsd_HostInfoNetBSD_h_ +#define lldb_Host_netbsd_HostInfoNetBSD_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class HostInfoNetBSD : public HostInfoPosix { +public: + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static FileSpec GetProgramFileSpec(); +}; +} + +#endif diff --git a/include/lldb/Host/openbsd/HostInfoOpenBSD.h b/include/lldb/Host/openbsd/HostInfoOpenBSD.h new file mode 100644 index 000000000..5a0388ffd --- /dev/null +++ b/include/lldb/Host/openbsd/HostInfoOpenBSD.h @@ -0,0 +1,27 @@ +//===-- HostInfoOpenBSD.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_Host_openbsd_HostInfoOpenBSD_h_ +#define lldb_Host_openbsd_HostInfoOpenBSD_h_ + +#include "lldb/Host/posix/HostInfoPosix.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class HostInfoOpenBSD : public HostInfoPosix { +public: + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static FileSpec GetProgramFileSpec(); +}; +} + +#endif diff --git a/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h b/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h new file mode 100644 index 000000000..b7e08eb33 --- /dev/null +++ b/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h @@ -0,0 +1,128 @@ +//===-- ConnectionFileDescriptorPosix.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_posix_ConnectionFileDescriptorPosix_h_ +#define liblldb_Host_posix_ConnectionFileDescriptorPosix_h_ + +// C++ Includes +#include +#include +#include + +#include "lldb/lldb-forward.h" + +// Other libraries and framework includes +// Project includes +#include "lldb/Host/Pipe.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Utility/Connection.h" +#include "lldb/Utility/IOObject.h" + +namespace lldb_private { + +class Status; +class Socket; +class SocketAddress; + +class ConnectionFileDescriptor : public Connection { +public: + static const char *LISTEN_SCHEME; + static const char *ACCEPT_SCHEME; + static const char *UNIX_ACCEPT_SCHEME; + static const char *CONNECT_SCHEME; + static const char *TCP_CONNECT_SCHEME; + static const char *UDP_SCHEME; + static const char *UNIX_CONNECT_SCHEME; + static const char *UNIX_ABSTRACT_CONNECT_SCHEME; + static const char *FD_SCHEME; + static const char *FILE_SCHEME; + + ConnectionFileDescriptor(bool child_processes_inherit = false); + + ConnectionFileDescriptor(int fd, bool owns_fd); + + ConnectionFileDescriptor(Socket *socket); + + ~ConnectionFileDescriptor() override; + + bool IsConnected() const override; + + lldb::ConnectionStatus Connect(llvm::StringRef s, Status *error_ptr) override; + + lldb::ConnectionStatus Disconnect(Status *error_ptr) override; + + size_t Read(void *dst, size_t dst_len, const Timeout &timeout, + lldb::ConnectionStatus &status, Status *error_ptr) override; + + size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, + Status *error_ptr) override; + + std::string GetURI() override; + + lldb::ConnectionStatus BytesAvailable(const Timeout &timeout, + Status *error_ptr); + + bool InterruptRead() override; + + lldb::IOObjectSP GetReadObject() override { return m_read_sp; } + + uint16_t GetListeningPort(uint32_t timeout_sec); + + bool GetChildProcessesInherit() const; + void SetChildProcessesInherit(bool child_processes_inherit); + +protected: + void OpenCommandPipe(); + + void CloseCommandPipe(); + + lldb::ConnectionStatus SocketListenAndAccept(llvm::StringRef host_and_port, + Status *error_ptr); + + lldb::ConnectionStatus ConnectTCP(llvm::StringRef host_and_port, + Status *error_ptr); + + lldb::ConnectionStatus ConnectUDP(llvm::StringRef args, Status *error_ptr); + + lldb::ConnectionStatus NamedSocketConnect(llvm::StringRef socket_name, + Status *error_ptr); + + lldb::ConnectionStatus NamedSocketAccept(llvm::StringRef socket_name, + Status *error_ptr); + + lldb::ConnectionStatus UnixAbstractSocketConnect(llvm::StringRef socket_name, + Status *error_ptr); + + lldb::IOObjectSP m_read_sp; + lldb::IOObjectSP m_write_sp; + + Predicate + m_port_predicate; // Used when binding to port zero to wait for the thread + // that creates the socket, binds and listens to resolve + // the port number. + + Pipe m_pipe; + std::recursive_mutex m_mutex; + std::atomic m_shutting_down; // This marks that we are shutting down so + // if we get woken up from + // BytesAvailable to disconnect, we won't try to read again. + bool m_waiting_for_accept; + bool m_child_processes_inherit; + + std::string m_uri; + +private: + void InitializeSocket(Socket *socket); + + DISALLOW_COPY_AND_ASSIGN(ConnectionFileDescriptor); +}; + +} // namespace lldb_private + +#endif // liblldb_ConnectionFileDescriptor_h_ diff --git a/include/lldb/Host/posix/DomainSocket.h b/include/lldb/Host/posix/DomainSocket.h new file mode 100644 index 000000000..e66b3f971 --- /dev/null +++ b/include/lldb/Host/posix/DomainSocket.h @@ -0,0 +1,35 @@ +//===-- DomainSocket.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DomainSocket_h_ +#define liblldb_DomainSocket_h_ + +#include "lldb/Host/Socket.h" + +namespace lldb_private { +class DomainSocket : public Socket { +public: + DomainSocket(bool should_close, bool child_processes_inherit); + + Status Connect(llvm::StringRef name) override; + Status Listen(llvm::StringRef name, int backlog) override; + Status Accept(Socket *&socket) override; + +protected: + DomainSocket(SocketProtocol protocol, bool child_processes_inherit); + + virtual size_t GetNameOffset() const; + virtual void DeleteSocketFile(llvm::StringRef name); + +private: + DomainSocket(NativeSocket socket, const DomainSocket &listen_socket); +}; +} + +#endif // ifndef liblldb_DomainSocket_h_ diff --git a/include/lldb/Host/posix/Fcntl.h b/include/lldb/Host/posix/Fcntl.h new file mode 100644 index 000000000..833a90584 --- /dev/null +++ b/include/lldb/Host/posix/Fcntl.h @@ -0,0 +1,25 @@ +//===-- Fcntl.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This file defines fcntl functions & structures + +#ifndef liblldb_Host_posix_Fcntl_h_ +#define liblldb_Host_posix_Fcntl_h_ + +#ifdef __ANDROID__ +#include +#endif + +#include + +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) +#endif + +#endif // liblldb_Host_posix_Fcntl_h_ diff --git a/include/lldb/Host/posix/HostInfoPosix.h b/include/lldb/Host/posix/HostInfoPosix.h new file mode 100644 index 000000000..34994aea4 --- /dev/null +++ b/include/lldb/Host/posix/HostInfoPosix.h @@ -0,0 +1,46 @@ +//===-- HostInfoPosix.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_Host_posix_HostInfoPosix_h_ +#define lldb_Host_posix_HostInfoPosix_h_ + +#include "lldb/Host/HostInfoBase.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class HostInfoPosix : public HostInfoBase { + friend class HostInfoBase; + +public: + static size_t GetPageSize(); + static bool GetHostname(std::string &s); + static const char *LookupUserName(uint32_t uid, std::string &user_name); + static const char *LookupGroupName(uint32_t gid, std::string &group_name); + + static uint32_t GetUserID(); + static uint32_t GetGroupID(); + static uint32_t GetEffectiveUserID(); + static uint32_t GetEffectiveGroupID(); + + static FileSpec GetDefaultShell(); + + static bool GetEnvironmentVar(const std::string &var_name, std::string &var); + +protected: + static bool ComputeSupportExeDirectory(FileSpec &file_spec); + static bool ComputeHeaderDirectory(FileSpec &file_spec); + static bool ComputePythonDirectory(FileSpec &file_spec); + static bool ComputeClangDirectory(FileSpec &file_spec); + static bool ComputePathRelativeToLibrary(FileSpec &file_spec, + llvm::StringRef dir); +}; +} + +#endif diff --git a/include/lldb/Host/posix/HostProcessPosix.h b/include/lldb/Host/posix/HostProcessPosix.h new file mode 100644 index 000000000..0a6d8822d --- /dev/null +++ b/include/lldb/Host/posix/HostProcessPosix.h @@ -0,0 +1,46 @@ +//===-- HostProcessPosix.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_Host_HostProcesPosix_h_ +#define lldb_Host_HostProcesPosix_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Host/HostNativeProcessBase.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +class FileSpec; + +class HostProcessPosix : public HostNativeProcessBase { +public: + HostProcessPosix(); + HostProcessPosix(lldb::process_t process); + ~HostProcessPosix() override; + + virtual Status Signal(int signo) const; + static Status Signal(lldb::process_t process, int signo); + + Status Terminate() override; + Status GetMainModule(FileSpec &file_spec) const override; + + lldb::pid_t GetProcessId() const override; + bool IsRunning() const override; + + HostThread StartMonitoring(const Host::MonitorChildProcessCallback &callback, + bool monitor_signals) override; +}; + +} // namespace lldb_private + +#endif // lldb_Host_HostProcesPosix_h_ diff --git a/include/lldb/Host/posix/HostThreadPosix.h b/include/lldb/Host/posix/HostThreadPosix.h new file mode 100644 index 000000000..c230a61bc --- /dev/null +++ b/include/lldb/Host/posix/HostThreadPosix.h @@ -0,0 +1,33 @@ +//===-- HostThreadPosix.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_Host_posix_HostThreadPosix_h_ +#define lldb_Host_posix_HostThreadPosix_h_ + +#include "lldb/Host/HostNativeThreadBase.h" + +namespace lldb_private { + +class HostThreadPosix : public HostNativeThreadBase { + DISALLOW_COPY_AND_ASSIGN(HostThreadPosix); + +public: + HostThreadPosix(); + HostThreadPosix(lldb::thread_t thread); + ~HostThreadPosix() override; + + Status Join(lldb::thread_result_t *result) override; + Status Cancel() override; + + Status Detach(); +}; + +} // namespace lldb_private + +#endif // lldb_Host_posix_HostThreadPosix_h_ diff --git a/include/lldb/Host/posix/LockFilePosix.h b/include/lldb/Host/posix/LockFilePosix.h new file mode 100644 index 000000000..a59a7fe3e --- /dev/null +++ b/include/lldb/Host/posix/LockFilePosix.h @@ -0,0 +1,36 @@ +//===-- LockFilePosix.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_posix_LockFilePosix_h_ +#define liblldb_Host_posix_LockFilePosix_h_ + +#include "lldb/Host/LockFileBase.h" + +namespace lldb_private { + +class LockFilePosix : public LockFileBase { +public: + explicit LockFilePosix(int fd); + ~LockFilePosix() override; + +protected: + Status DoWriteLock(const uint64_t start, const uint64_t len) override; + + Status DoTryWriteLock(const uint64_t start, const uint64_t len) override; + + Status DoReadLock(const uint64_t start, const uint64_t len) override; + + Status DoTryReadLock(const uint64_t start, const uint64_t len) override; + + Status DoUnlock() override; +}; + +} // namespace lldb_private + +#endif // liblldb_Host_posix_LockFilePosix_h_ diff --git a/include/lldb/Host/posix/PipePosix.h b/include/lldb/Host/posix/PipePosix.h new file mode 100644 index 000000000..8208b1b8b --- /dev/null +++ b/include/lldb/Host/posix/PipePosix.h @@ -0,0 +1,76 @@ +//===-- PipePosix.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_posix_PipePosix_h_ +#define liblldb_Host_posix_PipePosix_h_ +#if defined(__cplusplus) + +#include "lldb/Host/PipeBase.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class PipePosix PipePosix.h "lldb/Host/posix/PipePosix.h" +/// @brief A posix-based implementation of Pipe, a class that abtracts +/// unix style pipes. +/// +/// A class that abstracts the LLDB core from host pipe functionality. +//---------------------------------------------------------------------- +class PipePosix : public PipeBase { +public: + static int kInvalidDescriptor; + + PipePosix(); + PipePosix(int read_fd, int write_fd); + PipePosix(const PipePosix &) = delete; + PipePosix(PipePosix &&pipe_posix); + PipePosix &operator=(const PipePosix &) = delete; + PipePosix &operator=(PipePosix &&pipe_posix); + + ~PipePosix() override; + + Status CreateNew(bool child_process_inherit) override; + Status CreateNew(llvm::StringRef name, bool child_process_inherit) override; + Status CreateWithUniqueName(llvm::StringRef prefix, + bool child_process_inherit, + llvm::SmallVectorImpl &name) override; + Status OpenAsReader(llvm::StringRef name, + bool child_process_inherit) override; + Status + OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, + const std::chrono::microseconds &timeout) override; + + bool CanRead() const override; + bool CanWrite() const override; + + int GetReadFileDescriptor() const override; + int GetWriteFileDescriptor() const override; + int ReleaseReadFileDescriptor() override; + int ReleaseWriteFileDescriptor() override; + void CloseReadFileDescriptor() override; + void CloseWriteFileDescriptor() override; + + // Close both descriptors + void Close() override; + + Status Delete(llvm::StringRef name) override; + + Status Write(const void *buf, size_t size, size_t &bytes_written) override; + Status ReadWithTimeout(void *buf, size_t size, + const std::chrono::microseconds &timeout, + size_t &bytes_read) override; + +private: + int m_fds[2]; +}; + +} // namespace lldb_private + +#endif // #if defined(__cplusplus) +#endif // liblldb_Host_posix_PipePosix_h_ diff --git a/include/lldb/Host/posix/ProcessLauncherPosixFork.h b/include/lldb/Host/posix/ProcessLauncherPosixFork.h new file mode 100644 index 000000000..1193a20b4 --- /dev/null +++ b/include/lldb/Host/posix/ProcessLauncherPosixFork.h @@ -0,0 +1,25 @@ +//===-- ProcessLauncherPosixFork.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_Host_posix_ProcessLauncherPosixFork_h_ +#define lldb_Host_posix_ProcessLauncherPosixFork_h_ + +#include "lldb/Host/ProcessLauncher.h" + +namespace lldb_private { + +class ProcessLauncherPosixFork : public ProcessLauncher { +public: + HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, + Status &error) override; +}; + +} // end of namespace lldb_private + +#endif diff --git a/include/lldb/Host/windows/AutoHandle.h b/include/lldb/Host/windows/AutoHandle.h new file mode 100644 index 000000000..8c8c89767 --- /dev/null +++ b/include/lldb/Host/windows/AutoHandle.h @@ -0,0 +1,37 @@ +//===-- AutoHandle.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_Host_windows_AutoHandle_h_ +#define LLDB_lldb_Host_windows_AutoHandle_h_ + +#include "lldb/Host/windows/windows.h" + +namespace lldb_private { + +class AutoHandle { +public: + AutoHandle(HANDLE handle, HANDLE invalid_value = INVALID_HANDLE_VALUE) + : m_handle(handle), m_invalid_value(invalid_value) {} + + ~AutoHandle() { + if (m_handle != m_invalid_value) + ::CloseHandle(m_handle); + } + + bool IsValid() const { return m_handle != m_invalid_value; } + + HANDLE get() const { return m_handle; } + +private: + HANDLE m_handle; + HANDLE m_invalid_value; +}; +} + +#endif diff --git a/include/lldb/Host/windows/ConnectionGenericFileWindows.h b/include/lldb/Host/windows/ConnectionGenericFileWindows.h new file mode 100644 index 000000000..5907ff16d --- /dev/null +++ b/include/lldb/Host/windows/ConnectionGenericFileWindows.h @@ -0,0 +1,64 @@ +//===-- ConnectionGenericFileWindows.h --------------------------*- 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_windows_ConnectionGenericFileWindows_h_ +#define liblldb_Host_windows_ConnectionGenericFileWindows_h_ + +#include "lldb/Host/windows/windows.h" +#include "lldb/Utility/Connection.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +class Status; + +class ConnectionGenericFile : public lldb_private::Connection { +public: + ConnectionGenericFile(); + + ConnectionGenericFile(lldb::file_t file, bool owns_file); + + ~ConnectionGenericFile() override; + + bool IsConnected() const override; + + lldb::ConnectionStatus Connect(llvm::StringRef s, Status *error_ptr) override; + + lldb::ConnectionStatus Disconnect(Status *error_ptr) override; + + size_t Read(void *dst, size_t dst_len, const Timeout &timeout, + lldb::ConnectionStatus &status, Status *error_ptr) override; + + size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, + Status *error_ptr) override; + + std::string GetURI() override; + + bool InterruptRead() override; + +protected: + OVERLAPPED m_overlapped; + HANDLE m_file; + HANDLE m_event_handles[2]; + bool m_owns_file; + LARGE_INTEGER m_file_position; + + enum { kBytesAvailableEvent, kInterruptEvent }; + +private: + void InitializeEventHandles(); + void IncrementFilePointer(DWORD amount); + + std::string m_uri; + + DISALLOW_COPY_AND_ASSIGN(ConnectionGenericFile); +}; +} + +#endif diff --git a/include/lldb/Host/windows/HostInfoWindows.h b/include/lldb/Host/windows/HostInfoWindows.h new file mode 100644 index 000000000..9dfbf9359 --- /dev/null +++ b/include/lldb/Host/windows/HostInfoWindows.h @@ -0,0 +1,49 @@ +//===-- HostInfoWindows.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_Host_windows_HostInfoWindows_h_ +#define lldb_Host_windows_HostInfoWindows_h_ + +#include "lldb/Host/HostInfoBase.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class HostInfoWindows : public HostInfoBase { + friend class HostInfoBase; + +private: + // Static class, unconstructable. + HostInfoWindows(); + ~HostInfoWindows(); + +public: + static void Initialize(); + static void Terminate(); + + static size_t GetPageSize(); + + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static bool GetHostname(std::string &s); + static FileSpec GetProgramFileSpec(); + static FileSpec GetDefaultShell(); + + static bool GetEnvironmentVar(const std::string &var_name, std::string &var); + +protected: + static bool ComputePythonDirectory(FileSpec &file_spec); + +private: + static FileSpec m_program_filespec; +}; +} + +#endif diff --git a/include/lldb/Host/windows/HostProcessWindows.h b/include/lldb/Host/windows/HostProcessWindows.h new file mode 100644 index 000000000..4ef35337d --- /dev/null +++ b/include/lldb/Host/windows/HostProcessWindows.h @@ -0,0 +1,46 @@ +//===-- HostProcessWindows.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_Host_HostProcessWindows_h_ +#define lldb_Host_HostProcessWindows_h_ + +#include "lldb/Host/HostNativeProcessBase.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +class FileSpec; + +class HostProcessWindows : public HostNativeProcessBase { +public: + HostProcessWindows(); + explicit HostProcessWindows(lldb::process_t process); + ~HostProcessWindows(); + + void SetOwnsHandle(bool owns); + + Status Terminate() override; + Status GetMainModule(FileSpec &file_spec) const override; + + lldb::pid_t GetProcessId() const override; + bool IsRunning() const override; + + HostThread StartMonitoring(const Host::MonitorChildProcessCallback &callback, + bool monitor_signals) override; + +private: + static lldb::thread_result_t MonitorThread(void *thread_arg); + + void Close(); + + bool m_owns_handle; +}; +} + +#endif diff --git a/include/lldb/Host/windows/HostThreadWindows.h b/include/lldb/Host/windows/HostThreadWindows.h new file mode 100644 index 000000000..35d83c0ba --- /dev/null +++ b/include/lldb/Host/windows/HostThreadWindows.h @@ -0,0 +1,40 @@ +//===-- HostThreadWindows.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_Host_windows_HostThreadWindows_h_ +#define lldb_Host_windows_HostThreadWindows_h_ + +#include "lldb/Host/HostNativeThreadBase.h" + +#include "llvm/ADT/SmallString.h" + +namespace lldb_private { + +class HostThreadWindows : public HostNativeThreadBase { + DISALLOW_COPY_AND_ASSIGN(HostThreadWindows); + +public: + HostThreadWindows(); + HostThreadWindows(lldb::thread_t thread); + virtual ~HostThreadWindows(); + + void SetOwnsHandle(bool owns); + + virtual Status Join(lldb::thread_result_t *result); + virtual Status Cancel(); + virtual void Reset(); + + lldb::tid_t GetThreadId() const; + +private: + bool m_owns_handle; +}; +} + +#endif diff --git a/include/lldb/Host/windows/LockFileWindows.h b/include/lldb/Host/windows/LockFileWindows.h new file mode 100644 index 000000000..10456a1b8 --- /dev/null +++ b/include/lldb/Host/windows/LockFileWindows.h @@ -0,0 +1,42 @@ +//===-- LockFileWindows.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_posix_LockFileWindows_h_ +#define liblldb_Host_posix_LockFileWindows_h_ + +#include "lldb/Host/LockFileBase.h" +#include "lldb/Host/windows/windows.h" + +namespace lldb_private { + +class LockFileWindows : public LockFileBase { +public: + explicit LockFileWindows(int fd); + ~LockFileWindows(); + +protected: + Status DoWriteLock(const uint64_t start, const uint64_t len) override; + + Status DoTryWriteLock(const uint64_t start, const uint64_t len) override; + + Status DoReadLock(const uint64_t start, const uint64_t len) override; + + Status DoTryReadLock(const uint64_t start, const uint64_t len) override; + + Status DoUnlock() override; + + bool IsValidFile() const override; + +private: + HANDLE m_file; +}; + +} // namespace lldb_private + +#endif // liblldb_Host_posix_LockFileWindows_h_ diff --git a/include/lldb/Host/windows/PipeWindows.h b/include/lldb/Host/windows/PipeWindows.h new file mode 100644 index 000000000..86dec5a79 --- /dev/null +++ b/include/lldb/Host/windows/PipeWindows.h @@ -0,0 +1,81 @@ +//===-- PipePosix.h ---------------------------------------------*- 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_windows_PipeWindows_h_ +#define liblldb_Host_windows_PipeWindows_h_ + +#include "lldb/Host/PipeBase.h" +#include "lldb/Host/windows/windows.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Pipe PipeWindows.h "lldb/Host/windows/PipeWindows.h" +/// @brief A windows-based implementation of Pipe, a class that abtracts +/// unix style pipes. +/// +/// A class that abstracts the LLDB core from host pipe functionality. +//---------------------------------------------------------------------- +class PipeWindows : public PipeBase { +public: + PipeWindows(); + ~PipeWindows() override; + + Status CreateNew(bool child_process_inherit) override; + Status CreateNew(llvm::StringRef name, bool child_process_inherit) override; + Status CreateWithUniqueName(llvm::StringRef prefix, + bool child_process_inherit, + llvm::SmallVectorImpl &name) override; + Status OpenAsReader(llvm::StringRef name, + bool child_process_inherit) override; + Status + OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, + const std::chrono::microseconds &timeout) override; + + bool CanRead() const override; + bool CanWrite() const override; + + int GetReadFileDescriptor() const override; + int GetWriteFileDescriptor() const override; + int ReleaseReadFileDescriptor() override; + int ReleaseWriteFileDescriptor() override; + void CloseReadFileDescriptor() override; + void CloseWriteFileDescriptor() override; + + void Close() override; + + Status Delete(llvm::StringRef name) override; + + Status Write(const void *buf, size_t size, size_t &bytes_written) override; + Status ReadWithTimeout(void *buf, size_t size, + const std::chrono::microseconds &timeout, + size_t &bytes_read) override; + + // PipeWindows specific methods. These allow access to the underlying OS + // handle. + HANDLE GetReadNativeHandle(); + HANDLE GetWriteNativeHandle(); + +private: + Status OpenNamedPipe(llvm::StringRef name, bool child_process_inherit, + bool is_read); + + HANDLE m_read; + HANDLE m_write; + + int m_read_fd; + int m_write_fd; + + OVERLAPPED m_read_overlapped; + OVERLAPPED m_write_overlapped; +}; + +} // namespace lldb_private + +#endif // liblldb_Host_posix_PipePosix_h_ diff --git a/include/lldb/Host/windows/PosixApi.h b/include/lldb/Host/windows/PosixApi.h new file mode 100644 index 000000000..de70266a5 --- /dev/null +++ b/include/lldb/Host/windows/PosixApi.h @@ -0,0 +1,105 @@ +//===-- windows/PosixApi.h --------------------------------------*- 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_windows_PosixApi_h +#define liblldb_Host_windows_PosixApi_h + +#include "llvm/Support/Compiler.h" +#if !defined(LLVM_ON_WIN32) +#error "windows/PosixApi.h being #included on non Windows system!" +#endif + +// va_start, va_end, etc macros. +#include + +// time_t, timespec, etc. +#include + +#ifndef PATH_MAX +#define PATH_MAX 32768 +#endif + +#define O_NOCTTY 0 +#define O_NONBLOCK 0 +#define SIGTRAP 5 +#define SIGKILL 9 +#define SIGSTOP 20 + +#if defined(_MSC_VER) +#define S_IRUSR S_IREAD /* read, user */ +#define S_IWUSR S_IWRITE /* write, user */ +#define S_IXUSR 0 /* execute, user */ +#endif +#define S_IRGRP 0 /* read, group */ +#define S_IWGRP 0 /* write, group */ +#define S_IXGRP 0 /* execute, group */ +#define S_IROTH 0 /* read, others */ +#define S_IWOTH 0 /* write, others */ +#define S_IXOTH 0 /* execute, others */ +#define S_IRWXU 0 +#define S_IRWXG 0 +#define S_IRWXO 0 + +#ifdef _MSC_VER + +// PRIxxx format macros for printf() +#include + +// open(), close(), creat(), etc. +#include + +typedef unsigned short mode_t; + +// pyconfig.h typedefs this. We require python headers to be included before +// any LLDB headers, but there's no way to prevent python's pid_t definition +// from leaking, so this is the best option. +#ifndef NO_PID_T +typedef uint32_t pid_t; +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#define S_IFDIR _S_IFDIR + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif + +#endif // _MSC_VER + +// Various useful posix functions that are not present in Windows. We provide +// custom implementations. +int vasprintf(char **ret, const char *fmt, va_list ap); +char *strcasestr(const char *s, const char *find); +char *realpath(const char *name, char *resolved); + +int usleep(uint32_t useconds); +char *basename(char *path); +char *dirname(char *path); + +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); + +// empty functions +inline int posix_openpt(int flag) { LLVM_BUILTIN_UNREACHABLE; } + +inline int strerror_r(int errnum, char *buf, size_t buflen) { + LLVM_BUILTIN_UNREACHABLE; +} + +inline int unlockpt(int fd) { LLVM_BUILTIN_UNREACHABLE; } +inline int grantpt(int fd) { LLVM_BUILTIN_UNREACHABLE; } +inline char *ptsname(int fd) { LLVM_BUILTIN_UNREACHABLE; } + +inline pid_t fork(void) { LLVM_BUILTIN_UNREACHABLE; } +inline pid_t setsid(void) { LLVM_BUILTIN_UNREACHABLE; } + +#endif diff --git a/include/lldb/Host/windows/ProcessLauncherWindows.h b/include/lldb/Host/windows/ProcessLauncherWindows.h new file mode 100644 index 000000000..1df377d5e --- /dev/null +++ b/include/lldb/Host/windows/ProcessLauncherWindows.h @@ -0,0 +1,30 @@ +//===-- ProcessLauncherWindows.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_Host_windows_ProcessLauncherWindows_h_ +#define lldb_Host_windows_ProcessLauncherWindows_h_ + +#include "lldb/Host/ProcessLauncher.h" +#include "lldb/Host/windows/windows.h" + +namespace lldb_private { + +class ProcessLaunchInfo; + +class ProcessLauncherWindows : public ProcessLauncher { +public: + virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, + Status &error); + +protected: + HANDLE GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd); +}; +} + +#endif diff --git a/include/lldb/Host/windows/editlinewin.h b/include/lldb/Host/windows/editlinewin.h new file mode 100644 index 000000000..4522f0dd4 --- /dev/null +++ b/include/lldb/Host/windows/editlinewin.h @@ -0,0 +1,116 @@ +//===-- ELWrapper.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include + +// EditLine editor function return codes. +// For user-defined function interface +#define CC_NORM 0 +#define CC_NEWLINE 1 +#define CC_EOF 2 +#define CC_ARGHACK 3 +#define CC_REFRESH 4 +#define CC_CURSOR 5 +#define CC_ERROR 6 +#define CC_FATAL 7 +#define CC_REDISPLAY 8 +#define CC_REFRESH_BEEP 9 + +// el_set/el_get parameters +#define EL_PROMPT 0 // , el_pfunc_t +#define EL_TERMINAL 1 // , const char * +#define EL_EDITOR 2 // , const char * +#define EL_SIGNAL 3 // , int); +#define EL_BIND 4 // , const char *, ..., NULL +#define EL_TELLTC 5 // , const char *, ..., NULL +#define EL_SETTC 6 // , const char *, ..., NULL +#define EL_ECHOTC 7 // , const char *, ..., NULL +#define EL_SETTY 8 // , const char *, ..., NULL +#define EL_ADDFN 9 // , const char *, const char *, el_func_t +#define EL_HIST 10 // , hist_fun_t, const char * +#define EL_EDITMODE 11 // , int +#define EL_RPROMPT 12 // , el_pfunc_t +#define EL_GETCFN 13 // , el_rfunc_t +#define EL_CLIENTDATA 14 // , void * +#define EL_UNBUFFERED 15 // , int +#define EL_PREP_TERM 16 // , int +#define EL_GETTC 17 // , const char *, ..., NULL +#define EL_GETFP 18 // , int, FILE ** +#define EL_SETFP 19 // , int, FILE * +#define EL_REFRESH 20 // , void +#define EL_PROMPT_ESC 21 // , prompt_func, Char); set/get + +#define EL_BUILTIN_GETCFN (NULL) + +// history defines +#define H_FUNC 0 // , UTSL +#define H_SETSIZE 1 // , const int +#define H_GETSIZE 2 // , void +#define H_FIRST 3 // , void +#define H_LAST 4 // , void +#define H_PREV 5 // , void +#define H_NEXT 6 // , void +#define H_CURR 8 // , const int +#define H_SET 7 // , int +#define H_ADD 9 // , const char * +#define H_ENTER 10 // , const char * +#define H_APPEND 11 // , const char * +#define H_END 12 // , void +#define H_NEXT_STR 13 // , const char * +#define H_PREV_STR 14 // , const char * +#define H_NEXT_EVENT 15 // , const int +#define H_PREV_EVENT 16 // , const int +#define H_LOAD 17 // , const char * +#define H_SAVE 18 // , const char * +#define H_CLEAR 19 // , void +#define H_SETUNIQUE 20 // , int +#define H_GETUNIQUE 21 // , void +#define H_DEL 22 // , int + +struct EditLine {}; + +struct LineInfo { + const char *buffer; + const char *cursor; + const char *lastchar; +}; + +struct History {}; + +struct HistEvent { + int num; + const char *str; +}; + +extern "C" { +// edit line API +EditLine *el_init(const char *, FILE *, FILE *, FILE *); +const char *el_gets(EditLine *, int *); +int el_set(EditLine *, int, ...); + +void el_end(EditLine *); +void el_reset(EditLine *); +int el_getc(EditLine *, char *); +void el_push(EditLine *, const char *); +void el_beep(EditLine *); +int el_parse(EditLine *, int, const char **); +int el_get(EditLine *, int, ...); +int el_source(EditLine *, const char *); +void el_resize(EditLine *); +const LineInfo *el_line(EditLine *); +int el_insertstr(EditLine *, const char *); +void el_deletestr(EditLine *, int); + +// history API +History *history_init(void); +void history_end(History *); +int history(History *, HistEvent *, int, ...); +}; \ No newline at end of file diff --git a/include/lldb/Host/windows/windows.h b/include/lldb/Host/windows/windows.h new file mode 100644 index 000000000..3dc9f77f8 --- /dev/null +++ b/include/lldb/Host/windows/windows.h @@ -0,0 +1,31 @@ +//===-- lldb-windows.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_windows_h_ +#define LLDB_lldb_windows_h_ + +#define NTDDI_VERSION NTDDI_VISTA +#undef _WIN32_WINNT // undef a previous definition to avoid warning +#define _WIN32_WINNT _WIN32_WINNT_VISTA +#define WIN32_LEAN_AND_MEAN +#define NOGDI +#undef NOMINMAX // undef a previous definition to avoid warning +#define NOMINMAX +#include +#undef GetUserName +#undef LoadImage +#undef CreateProcess +#undef far +#undef near +#undef FAR +#undef NEAR +#define FAR +#define NEAR + +#endif // LLDB_lldb_windows_h_ diff --git a/include/lldb/Initialization/SystemInitializer.h b/include/lldb/Initialization/SystemInitializer.h new file mode 100644 index 000000000..58bbb44b1 --- /dev/null +++ b/include/lldb/Initialization/SystemInitializer.h @@ -0,0 +1,24 @@ +//===-- SystemInitializer.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H +#define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_H + +namespace lldb_private { +class SystemInitializer { +public: + SystemInitializer(); + virtual ~SystemInitializer(); + + virtual void Initialize() = 0; + virtual void Terminate() = 0; +}; +} + +#endif diff --git a/include/lldb/Initialization/SystemInitializerCommon.h b/include/lldb/Initialization/SystemInitializerCommon.h new file mode 100644 index 000000000..2a9851c6a --- /dev/null +++ b/include/lldb/Initialization/SystemInitializerCommon.h @@ -0,0 +1,37 @@ +//===-- SystemInitializerCommon.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_INITIALIZATION_SYSTEM_INITIALIZER_COMMON_H +#define LLDB_INITIALIZATION_SYSTEM_INITIALIZER_COMMON_H + +#include "SystemInitializer.h" + +namespace lldb_private { +//------------------------------------------------------------------ +/// Initializes common lldb functionality. +/// +/// This class is responsible for initializing a subset of lldb +/// useful to both debug servers and debug clients. Debug servers +/// do not use all of LLDB and desire small binary sizes, so this +/// functionality is separate. This class is used by constructing +/// an instance of SystemLifetimeManager with this class passed to +/// the constructor. +//------------------------------------------------------------------ +class SystemInitializerCommon : public SystemInitializer { +public: + SystemInitializerCommon(); + ~SystemInitializerCommon() override; + + void Initialize() override; + void Terminate() override; +}; + +} // namespace lldb_private + +#endif // LLDB_INITIALIZATION_SYSTEM_INITIALIZER_COMMON_H diff --git a/include/lldb/Initialization/SystemLifetimeManager.h b/include/lldb/Initialization/SystemLifetimeManager.h new file mode 100644 index 000000000..0ebd4a50a --- /dev/null +++ b/include/lldb/Initialization/SystemLifetimeManager.h @@ -0,0 +1,41 @@ +//===-- SystemLifetimeManager.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_INITIALIZATION_SYSTEM_LIFETIME_MANAGER_H +#define LLDB_INITIALIZATION_SYSTEM_LIFETIME_MANAGER_H + +#include "lldb/lldb-private-types.h" + +#include +#include + +namespace lldb_private { +class SystemInitializer; + +class SystemLifetimeManager { +public: + SystemLifetimeManager(); + ~SystemLifetimeManager(); + + void Initialize(std::unique_ptr initializer, + LoadPluginCallbackType plugin_callback); + void Terminate(); + +private: + std::recursive_mutex m_mutex; + std::unique_ptr m_initializer; + bool m_initialized; + + // Noncopyable. + SystemLifetimeManager(const SystemLifetimeManager &other) = delete; + SystemLifetimeManager &operator=(const SystemLifetimeManager &other) = delete; +}; +} + +#endif diff --git a/include/lldb/Interpreter/Args.h b/include/lldb/Interpreter/Args.h new file mode 100644 index 000000000..98046cd59 --- /dev/null +++ b/include/lldb/Interpreter/Args.h @@ -0,0 +1,479 @@ +//===-- 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 +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +// Project includes +#include "lldb/Utility/Status.h" +#include "lldb/lldb-private-types.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +struct Option; + +typedef std::vector> OptionArgVector; +typedef std::shared_ptr OptionArgVectorSP; + +struct OptionArgElement { + enum { eUnrecognizedArg = -1, eBareDash = -2, eBareDoubleDash = -3 }; + + OptionArgElement(int defs_index, int pos, int arg_pos) + : opt_defs_index(defs_index), opt_pos(pos), opt_arg_pos(arg_pos) {} + + int opt_defs_index; + int opt_pos; + int opt_arg_pos; +}; + +typedef std::vector OptionElementVector; + +//---------------------------------------------------------------------- +/// @class Args Args.h "lldb/Interpreter/Args.h" +/// @brief A command line argument class. +/// +/// The Args class is designed to be fed a command line. The +/// command line is copied into an internal buffer and then split up +/// into arguments. Arguments are space delimited if there are no quotes +/// (single, double, or backtick quotes) surrounding the argument. Spaces +/// can be escaped using a \ character to avoid having to surround an +/// argument that contains a space with quotes. +//---------------------------------------------------------------------- +class Args { +public: + struct ArgEntry { + private: + friend class Args; + std::unique_ptr ptr; + + char *data() { return ptr.get(); } + + public: + ArgEntry() = default; + ArgEntry(llvm::StringRef str, char quote); + + llvm::StringRef ref; + char quote; + const char *c_str() const { return ptr.get(); } + }; + + //------------------------------------------------------------------ + /// 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(llvm::StringRef) + //------------------------------------------------------------------ + Args(llvm::StringRef command = llvm::StringRef()); + + Args(const Args &rhs); + + Args &operator=(const Args &rhs); + + //------------------------------------------------------------------ + /// Destructor. + //------------------------------------------------------------------ + ~Args(); + + //------------------------------------------------------------------ + /// Dump all entries to the stream \a s using label \a label_name. + /// + /// If label_name is nullptr, the dump operation is skipped. + /// + /// @param[in] s + /// The stream to which to dump all arguments in the argument + /// vector. + /// @param[in] label_name + /// The label_name to use as the label printed for each + /// entry of the args like so: + /// {label_name}[{index}]={value} + //------------------------------------------------------------------ + void Dump(Stream &s, const char *label_name = "argv") const; + + //------------------------------------------------------------------ + /// 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 command StringRef 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(llvm::StringRef command); + + bool GetCommandString(std::string &command) const; + + bool GetQuotedCommandString(std::string &command) const; + + //------------------------------------------------------------------ + /// Gets the number of arguments left in this command object. + /// + /// @return + /// The number or arguments in this object. + //------------------------------------------------------------------ + size_t GetArgumentCount() const; + bool empty() const { return GetArgumentCount() == 0; } + + //------------------------------------------------------------------ + /// 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; + + llvm::ArrayRef entries() const { return m_entries; } + char GetArgumentQuoteCharAtIndex(size_t idx) const; + + std::vector::const_iterator begin() const { + return m_entries.begin(); + } + std::vector::const_iterator end() const { return m_entries.end(); } + + size_t size() const { return GetArgumentCount(); } + const ArgEntry &operator[](size_t n) const { return m_entries[n]; } + + //------------------------------------------------------------------ + /// 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; + + //------------------------------------------------------------------ + /// Gets the argument as an ArrayRef. Note that the return value does *not* + /// have a nullptr const char * at the end, as the size of the list is + /// embedded in the ArrayRef object. + //------------------------------------------------------------------ + llvm::ArrayRef GetArgumentArrayRef() const { + return llvm::makeArrayRef(m_argv).drop_back(); + } + + //------------------------------------------------------------------ + /// 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. + //------------------------------------------------------------------ + void AppendArgument(llvm::StringRef arg_str, char quote_char = '\0'); + + void AppendArguments(const Args &rhs); + + void AppendArguments(const char **argv); + + //------------------------------------------------------------------ + /// Insert the argument value at index \a idx to \a arg_cstr. + /// + /// @param[in] idx + /// The index of where to insert the argument. + /// + /// @param[in] arg_cstr + /// The new argument as a NULL terminated C string. + /// + /// @param[in] quote_char + /// If the argument was originally quoted, put in the quote char here. + /// + /// @return + /// The NULL terminated C string of the copy of \a arg_cstr. + //------------------------------------------------------------------ + void InsertArgumentAtIndex(size_t idx, llvm::StringRef arg_str, + 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. + //------------------------------------------------------------------ + void ReplaceArgumentAtIndex(size_t idx, llvm::StringRef arg_str, + char quote_char = '\0'); + + //------------------------------------------------------------------ + /// Deletes the argument value at index + /// if \a idx is a valid argument index. + /// + /// @param[in] idx + /// The index of the argument that will have its value replaced. + /// + //------------------------------------------------------------------ + void DeleteArgumentAtIndex(size_t idx); + + //------------------------------------------------------------------ + /// Sets the argument vector value, optionally copying all + /// arguments into an internal buffer. + /// + /// Sets the arguments to match those found in \a argv. All argument + /// strings will be copied into an internal buffers. + // + // FIXME: Handle the quote character somehow. + //------------------------------------------------------------------ + void SetArguments(size_t argc, const char **argv); + + void SetArguments(const char **argv); + + //------------------------------------------------------------------ + /// Shifts the first argument C string value of the array off the + /// argument array. + /// + /// The string value will be freed, so a copy of the string should + /// be made by calling Args::GetArgumentAtIndex (size_t) const + /// first and copying the returned value before calling + /// Args::Shift(). + /// + /// @see Args::GetArgumentAtIndex (size_t) const + //------------------------------------------------------------------ + void Shift(); + + //------------------------------------------------------------------ + /// Inserts a class owned copy of \a arg_cstr at the beginning of + /// the argument vector. + /// + /// A copy \a arg_cstr will be made. + /// + /// @param[in] arg_cstr + /// The argument to push on the front of the argument stack. + /// + /// @param[in] quote_char + /// If the argument was originally quoted, put in the quote char here. + //------------------------------------------------------------------ + void Unshift(llvm::StringRef arg_str, 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 arguments that + /// get processed start at the second argument. The first argument + /// is assumed to be the command and will not be touched. + /// + /// param[in] platform_sp + /// The platform used for option validation. This is necessary + /// because an empty execution_context is not enough to get us + /// to a reasonable platform. If the platform isn't given, + /// we'll try to get it from the execution context. If we can't + /// get it from the execution context, we'll skip validation. + /// + /// param[in] require_validation + /// When true, it will fail option parsing if validation could + /// not occur due to not having a platform. + /// + /// @see class Options + //------------------------------------------------------------------ + Status ParseOptions(Options &options, ExecutionContext *execution_context, + lldb::PlatformSP platform_sp, bool require_validation); + + bool IsPositionalArgument(const char *arg); + + // The following works almost identically to ParseOptions, except that no + // option is required to have arguments, and it builds up the + // option_arg_vector as it parses the options. + + std::string ParseAliasOptions(Options &options, CommandReturnObject &result, + OptionArgVector *option_arg_vector, + llvm::StringRef raw_input_line); + + void ParseArgsForCompletion(Options &options, + OptionElementVector &option_element_vector, + uint32_t cursor_index); + + //------------------------------------------------------------------ + // Clear the arguments. + // + // For re-setting or blanking out the list of arguments. + //------------------------------------------------------------------ + void Clear(); + + static const char *StripSpaces(std::string &s, bool leading = true, + bool trailing = true, + bool return_null_if_empty = true); + + static bool UInt64ValueIsValidForByteSize(uint64_t uval64, + size_t total_byte_size) { + if (total_byte_size > 8) + return false; + + if (total_byte_size == 8) + return true; + + const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; + return uval64 <= max; + } + + static bool SInt64ValueIsValidForByteSize(int64_t sval64, + size_t total_byte_size) { + if (total_byte_size > 8) + return false; + + if (total_byte_size == 8) + return true; + + const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; + const int64_t min = ~(max); + return min <= sval64 && sval64 <= max; + } + + static lldb::addr_t StringToAddress(const ExecutionContext *exe_ctx, + llvm::StringRef s, + lldb::addr_t fail_value, Status *error); + + static bool StringToBoolean(llvm::StringRef s, bool fail_value, + bool *success_ptr); + + static char StringToChar(llvm::StringRef s, char fail_value, + bool *success_ptr); + + static int64_t StringToOptionEnum(llvm::StringRef s, + OptionEnumValueElement *enum_values, + int32_t fail_value, Status &error); + + static lldb::ScriptLanguage + StringToScriptLanguage(llvm::StringRef s, lldb::ScriptLanguage fail_value, + bool *success_ptr); + + // TODO: Use StringRef + static Status StringToFormat(const char *s, lldb::Format &format, + size_t *byte_size_ptr); // If non-NULL, then a + // byte size can precede + // the format character + + static lldb::Encoding + StringToEncoding(llvm::StringRef s, + lldb::Encoding fail_value = lldb::eEncodingInvalid); + + static uint32_t StringToGenericRegister(llvm::StringRef s); + + static bool StringToVersion(llvm::StringRef string, uint32_t &major, + uint32_t &minor, uint32_t &update); + + static const char *GetShellSafeArgument(const FileSpec &shell, + const char *unsafe_arg, + std::string &safe_arg); + + // EncodeEscapeSequences will change the textual representation of common + // escape sequences like "\n" (two characters) into a single '\n'. It does + // this for all of the supported escaped sequences and for the \0ooo (octal) + // and \xXX (hex). The resulting "dst" string will contain the character + // versions of all supported escape sequences. The common supported escape + // sequences are: "\a", "\b", "\f", "\n", "\r", "\t", "\v", "\'", "\"", "\\". + + static void EncodeEscapeSequences(const char *src, std::string &dst); + + // ExpandEscapeSequences will change a string of possibly non-printable + // characters and expand them into text. So '\n' will turn into two characters + // like "\n" which is suitable for human reading. When a character is not + // printable and isn't one of the common in escape sequences listed in the + // help for EncodeEscapeSequences, then it will be encoded as octal. Printable + // characters are left alone. + static void ExpandEscapedCharacters(const char *src, std::string &dst); + + static std::string EscapeLLDBCommandArgument(const std::string &arg, + char quote_char); + + //------------------------------------------------------------------ + /// Add or replace an environment variable with the given value. + /// + /// This command adds the environment variable if it is not already + /// present using the given value. If the environment variable is + /// already in the list, it replaces the first such occurrence + /// with the new value. + //------------------------------------------------------------------ + void AddOrReplaceEnvironmentVariable(llvm::StringRef env_var_name, + llvm::StringRef new_value); + + /// Return whether a given environment variable exists. + /// + /// This command treats Args like a list of environment variables, + /// as used in ProcessLaunchInfo. It treats each argument as + /// an {env_var_name}={value} or an {env_var_name} entry. + /// + /// @param[in] env_var_name + /// Specifies the name of the environment variable to check. + /// + /// @param[out] argument_index + /// If non-null, then when the environment variable is found, + /// the index of the argument position will be returned in + /// the size_t pointed to by this argument. + /// + /// @return + /// true if the specified env var name exists in the list in + /// either of the above-mentioned formats; otherwise, false. + //------------------------------------------------------------------ + bool ContainsEnvironmentVariable(llvm::StringRef env_var_name, + size_t *argument_index = nullptr) const; + +private: + size_t FindArgumentIndexForOption(Option *long_options, + int long_options_index) const; + + std::vector m_entries; + std::vector m_argv; + + void UpdateArgsAfterOptionParsing(); +}; + +} // namespace lldb_private + +#endif // liblldb_Command_h_ diff --git a/include/lldb/Interpreter/CommandAlias.h b/include/lldb/Interpreter/CommandAlias.h new file mode 100644 index 000000000..4658a1e44 --- /dev/null +++ b/include/lldb/Interpreter/CommandAlias.h @@ -0,0 +1,94 @@ +//===-- CommandAlias.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandAlias_h_ +#define liblldb_CommandAlias_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/lldb-forward.h" + +namespace lldb_private { +class CommandAlias : public CommandObject { +public: + typedef std::unique_ptr UniquePointer; + + CommandAlias(CommandInterpreter &interpreter, lldb::CommandObjectSP cmd_sp, + llvm::StringRef options_args, llvm::StringRef name, + llvm::StringRef help = llvm::StringRef(), + llvm::StringRef syntax = llvm::StringRef(), uint32_t flags = 0); + + void GetAliasExpansion(StreamString &help_string) const; + + bool IsValid() const { return m_underlying_command_sp && m_option_args_sp; } + + explicit operator bool() const { return IsValid(); } + + bool WantsRawCommandString() override; + + bool WantsCompletion() override; + + int HandleCompletion(Args &input, int &cursor_index, + int &cursor_char_position, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches) override; + + int HandleArgumentCompletion(Args &input, int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, int max_return_elements, + bool &word_complete, + StringList &matches) override; + + Options *GetOptions() override; + + bool IsAlias() override { return true; } + + bool IsDashDashCommand() override; + + llvm::StringRef GetHelp() override; + + llvm::StringRef GetHelpLong() override; + + void SetHelp(llvm::StringRef str) override; + + void SetHelpLong(llvm::StringRef str) override; + + bool Execute(const char *args_string, CommandReturnObject &result) override; + + lldb::CommandObjectSP GetUnderlyingCommand() { + return m_underlying_command_sp; + } + OptionArgVectorSP GetOptionArguments() const { return m_option_args_sp; } + const char *GetOptionString() { return m_option_string.c_str(); } + + // this takes an alias - potentially nested (i.e. an alias to an alias) + // and expands it all the way to a non-alias command + std::pair Desugar(); + +protected: + bool IsNestedAlias(); + +private: + lldb::CommandObjectSP m_underlying_command_sp; + std::string m_option_string; + OptionArgVectorSP m_option_args_sp; + LazyBool m_is_dashdash_alias; + bool m_did_set_help : 1; + bool m_did_set_help_long : 1; +}; +} // namespace lldb_private + +#endif // liblldb_CommandAlias_h_ diff --git a/include/lldb/Interpreter/CommandCompletions.h b/include/lldb/Interpreter/CommandCompletions.h new file mode 100644 index 000000000..8bac3e863 --- /dev/null +++ b/include/lldb/Interpreter/CommandCompletions.h @@ -0,0 +1,259 @@ +//===-- CommandCompletions.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_CommandCompletions_h_ +#define lldb_CommandCompletions_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/FileSpecList.h" +#include "lldb/Core/SearchFilter.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/lldb-private.h" + +#include "llvm/ADT/Twine.h" + +namespace lldb_private { +class TildeExpressionResolver; +class CommandCompletions { +public: + //---------------------------------------------------------------------- + // This is the command completion callback that is used to complete the + // argument of the option + // it is bound to (in the OptionDefinition table below). Return the total + // number of matches. + //---------------------------------------------------------------------- + typedef int (*CompletionCallback)( + CommandInterpreter &interpreter, + llvm::StringRef completion_str, // This is the argument we are completing + int match_start_point, // This is the point in the list of matches that + // you should start returning elements + int max_return_elements, // This is the number of matches requested. + lldb_private::SearchFilter + *searcher, // A search filter to limit the search... + bool &word_complete, + lldb_private::StringList &matches); // The array of matches we return. + typedef enum { + eNoCompletion = 0u, + eSourceFileCompletion = (1u << 0), + eDiskFileCompletion = (1u << 1), + eDiskDirectoryCompletion = (1u << 2), + eSymbolCompletion = (1u << 3), + eModuleCompletion = (1u << 4), + eSettingsNameCompletion = (1u << 5), + ePlatformPluginCompletion = (1u << 6), + eArchitectureCompletion = (1u << 7), + eVariablePathCompletion = (1u << 8), + // This item serves two purposes. It is the last element in the enum, + // so you can add custom enums starting from here in your Option class. + // Also if you & in this bit the base code will not process the option. + eCustomCompletion = (1u << 9) + } CommonCompletionTypes; + + struct CommonCompletionElement { + uint32_t type; + CompletionCallback callback; + }; + + static bool InvokeCommonCompletionCallbacks( + CommandInterpreter &interpreter, uint32_t completion_mask, + llvm::StringRef completion_str, int match_start_point, + int max_return_elements, SearchFilter *searcher, bool &word_complete, + StringList &matches); + + //---------------------------------------------------------------------- + // These are the generic completer functions: + //---------------------------------------------------------------------- + static int DiskFiles(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, int match_start_point, + int max_return_elements, SearchFilter *searcher, + bool &word_complete, StringList &matches); + + static int DiskFiles(const llvm::Twine &partial_file_name, + StringList &matches, TildeExpressionResolver &Resolver); + + static int DiskDirectories(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, + int match_start_point, int max_return_elements, + SearchFilter *searcher, bool &word_complete, + StringList &matches); + + static int DiskDirectories(const llvm::Twine &partial_file_name, + StringList &matches, + TildeExpressionResolver &Resolver); + + static int SourceFiles(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, + int match_start_point, int max_return_elements, + SearchFilter *searcher, bool &word_complete, + StringList &matches); + + static int Modules(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, int match_start_point, + int max_return_elements, SearchFilter *searcher, + bool &word_complete, lldb_private::StringList &matches); + + static int Symbols(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, int match_start_point, + int max_return_elements, SearchFilter *searcher, + bool &word_complete, lldb_private::StringList &matches); + + static int SettingsNames(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, + int match_start_point, int max_return_elements, + SearchFilter *searcher, bool &word_complete, + lldb_private::StringList &matches); + + static int PlatformPluginNames(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, + int match_start_point, int max_return_elements, + SearchFilter *searcher, bool &word_complete, + lldb_private::StringList &matches); + + static int ArchitectureNames(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, + int match_start_point, int max_return_elements, + SearchFilter *searcher, bool &word_complete, + lldb_private::StringList &matches); + + static int VariablePath(CommandInterpreter &interpreter, + llvm::StringRef partial_file_name, + int match_start_point, int max_return_elements, + SearchFilter *searcher, bool &word_complete, + lldb_private::StringList &matches); + + //---------------------------------------------------------------------- + // The Completer class is a convenient base class for building searchers + // that go along with the SearchFilter passed to the standard Completer + // functions. + //---------------------------------------------------------------------- + class Completer : public Searcher { + public: + Completer(CommandInterpreter &interpreter, llvm::StringRef completion_str, + int match_start_point, int max_return_elements, + StringList &matches); + + ~Completer() override; + + CallbackReturn SearchCallback(SearchFilter &filter, SymbolContext &context, + Address *addr, bool complete) override = 0; + + Depth GetDepth() override = 0; + + virtual size_t DoCompletion(SearchFilter *filter) = 0; + + protected: + CommandInterpreter &m_interpreter; + std::string m_completion_str; + int m_match_start_point; + int m_max_return_elements; + StringList &m_matches; + + private: + DISALLOW_COPY_AND_ASSIGN(Completer); + }; + + //---------------------------------------------------------------------- + // SourceFileCompleter implements the source file completer + //---------------------------------------------------------------------- + class SourceFileCompleter : public Completer { + public: + SourceFileCompleter(CommandInterpreter &interpreter, + bool include_support_files, + llvm::StringRef completion_str, int match_start_point, + int max_return_elements, StringList &matches); + + Searcher::Depth GetDepth() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, + Address *addr, + bool complete) override; + + size_t DoCompletion(SearchFilter *filter) override; + + private: + bool m_include_support_files; + FileSpecList m_matching_files; + const char *m_file_name; + const char *m_dir_name; + + DISALLOW_COPY_AND_ASSIGN(SourceFileCompleter); + }; + + //---------------------------------------------------------------------- + // ModuleCompleter implements the module completer + //---------------------------------------------------------------------- + class ModuleCompleter : public Completer { + public: + ModuleCompleter(CommandInterpreter &interpreter, + llvm::StringRef completion_str, int match_start_point, + int max_return_elements, StringList &matches); + + Searcher::Depth GetDepth() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, + Address *addr, + bool complete) override; + + size_t DoCompletion(SearchFilter *filter) override; + + private: + const char *m_file_name; + const char *m_dir_name; + + DISALLOW_COPY_AND_ASSIGN(ModuleCompleter); + }; + + //---------------------------------------------------------------------- + // SymbolCompleter implements the symbol completer + //---------------------------------------------------------------------- + class SymbolCompleter : public Completer { + public: + SymbolCompleter(CommandInterpreter &interpreter, + llvm::StringRef completion_str, int match_start_point, + int max_return_elements, StringList &matches); + + Searcher::Depth GetDepth() override; + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, + Address *addr, + bool complete) override; + + size_t DoCompletion(SearchFilter *filter) override; + + private: + // struct NameCmp { + // bool operator() (const ConstString& lhs, const ConstString& + // rhs) const + // { + // return lhs < rhs; + // } + // }; + + RegularExpression m_regex; + typedef std::set collection; + collection m_match_set; + + DISALLOW_COPY_AND_ASSIGN(SymbolCompleter); + }; + +private: + static CommonCompletionElement g_common_completions[]; +}; + +} // namespace lldb_private + +#endif // lldb_CommandCompletions_h_ diff --git a/include/lldb/Interpreter/CommandHistory.h b/include/lldb/Interpreter/CommandHistory.h new file mode 100644 index 000000000..faef220bb --- /dev/null +++ b/include/lldb/Interpreter/CommandHistory.h @@ -0,0 +1,63 @@ +//===-- CommandHistory.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandHistory_h_ +#define liblldb_CommandHistory_h_ + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Stream.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class CommandHistory { +public: + CommandHistory(); + + ~CommandHistory(); + + size_t GetSize() const; + + bool IsEmpty() const; + + llvm::Optional FindString(llvm::StringRef input_str) const; + + llvm::StringRef GetStringAtIndex(size_t idx) const; + + llvm::StringRef operator[](size_t idx) const; + + llvm::StringRef GetRecentmostString() const; + + void AppendString(llvm::StringRef str, bool reject_if_dupe = true); + + void Clear(); + + void Dump(Stream &stream, size_t start_idx = 0, + size_t stop_idx = SIZE_MAX) const; + + static const char g_repeat_char = '!'; + +private: + DISALLOW_COPY_AND_ASSIGN(CommandHistory); + + typedef std::vector History; + mutable std::recursive_mutex m_mutex; + History m_history; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandHistory_h_ diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h new file mode 100644 index 000000000..73bd7d6e6 --- /dev/null +++ b/include/lldb/Interpreter/CommandInterpreter.h @@ -0,0 +1,558 @@ +//===-- 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 +#include +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Event.h" +#include "lldb/Core/IOHandler.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandAlias.h" +#include "lldb/Interpreter/CommandHistory.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StringList.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class CommandInterpreterRunOptions { +public: + //------------------------------------------------------------------ + /// Construct a CommandInterpreterRunOptions object. + /// This class is used to control all the instances where we run multiple + /// commands, e.g. + /// HandleCommands, HandleCommandsFromFile, RunCommandInterpreter. + /// The meanings of the options in this object are: + /// + /// @param[in] stop_on_continue + /// If \b true execution will end on the first command that causes the + /// process in the + /// execution context to continue. If \false, we won't check the execution + /// status. + /// @param[in] stop_on_error + /// If \b true execution will end on the first command that causes an + /// error. + /// @param[in] stop_on_crash + /// If \b true when a command causes the target to run, and the end of the + /// run is a + /// signal or exception, stop executing the commands. + /// @param[in] echo_commands + /// If \b true echo the command before executing it. If \false, execute + /// silently. + /// @param[in] print_results + /// If \b true print the results of the command after executing it. If + /// \false, execute silently. + /// @param[in] add_to_history + /// If \b true add the commands to the command history. If \false, don't + /// add them. + //------------------------------------------------------------------ + CommandInterpreterRunOptions(LazyBool stop_on_continue, + LazyBool stop_on_error, LazyBool stop_on_crash, + LazyBool echo_commands, LazyBool print_results, + LazyBool add_to_history) + : m_stop_on_continue(stop_on_continue), m_stop_on_error(stop_on_error), + m_stop_on_crash(stop_on_crash), m_echo_commands(echo_commands), + m_print_results(print_results), m_add_to_history(add_to_history) {} + + CommandInterpreterRunOptions() + : m_stop_on_continue(eLazyBoolCalculate), + m_stop_on_error(eLazyBoolCalculate), + m_stop_on_crash(eLazyBoolCalculate), + m_echo_commands(eLazyBoolCalculate), + m_print_results(eLazyBoolCalculate), + m_add_to_history(eLazyBoolCalculate) {} + + void SetSilent(bool silent) { + LazyBool value = silent ? eLazyBoolNo : eLazyBoolYes; + + m_echo_commands = value; + m_print_results = value; + m_add_to_history = value; + } + // These return the default behaviors if the behavior is not + // eLazyBoolCalculate. + // But I've also left the ivars public since for different ways of running the + // interpreter you might want to force different defaults... In that case, + // just grab + // the LazyBool ivars directly and do what you want with eLazyBoolCalculate. + bool GetStopOnContinue() const { return DefaultToNo(m_stop_on_continue); } + + void SetStopOnContinue(bool stop_on_continue) { + m_stop_on_continue = stop_on_continue ? eLazyBoolYes : eLazyBoolNo; + } + + bool GetStopOnError() const { return DefaultToNo(m_stop_on_continue); } + + void SetStopOnError(bool stop_on_error) { + m_stop_on_error = stop_on_error ? eLazyBoolYes : eLazyBoolNo; + } + + bool GetStopOnCrash() const { return DefaultToNo(m_stop_on_crash); } + + void SetStopOnCrash(bool stop_on_crash) { + m_stop_on_crash = stop_on_crash ? eLazyBoolYes : eLazyBoolNo; + } + + bool GetEchoCommands() const { return DefaultToYes(m_echo_commands); } + + void SetEchoCommands(bool echo_commands) { + m_echo_commands = echo_commands ? eLazyBoolYes : eLazyBoolNo; + } + + bool GetPrintResults() const { return DefaultToYes(m_print_results); } + + void SetPrintResults(bool print_results) { + m_print_results = print_results ? eLazyBoolYes : eLazyBoolNo; + } + + bool GetAddToHistory() const { return DefaultToYes(m_add_to_history); } + + void SetAddToHistory(bool add_to_history) { + m_add_to_history = add_to_history ? eLazyBoolYes : eLazyBoolNo; + } + + LazyBool m_stop_on_continue; + LazyBool m_stop_on_error; + LazyBool m_stop_on_crash; + LazyBool m_echo_commands; + LazyBool m_print_results; + LazyBool m_add_to_history; + +private: + static bool DefaultToYes(LazyBool flag) { + switch (flag) { + case eLazyBoolNo: + return false; + default: + return true; + } + } + + static bool DefaultToNo(LazyBool flag) { + switch (flag) { + case eLazyBoolYes: + return true; + default: + return false; + } + } +}; + +class CommandInterpreter : public Broadcaster, + public Properties, + public IOHandlerDelegate { +public: + enum { + eBroadcastBitThreadShouldExit = (1 << 0), + eBroadcastBitResetPrompt = (1 << 1), + eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit + eBroadcastBitAsynchronousOutputData = (1 << 3), + eBroadcastBitAsynchronousErrorData = (1 << 4) + }; + + enum ChildrenTruncatedWarningStatus // tristate boolean to manage children + // truncation warning + { eNoTruncation = 0, // never truncated + eUnwarnedTruncation = 1, // truncated but did not notify + eWarnedTruncation = 2 // truncated and notified + }; + + enum CommandTypes { + eCommandTypesBuiltin = 0x0001, // native commands such as "frame" + eCommandTypesUserDef = 0x0002, // scripted commands + eCommandTypesAliases = 0x0004, // aliases such as "po" + eCommandTypesHidden = 0x0008, // commands prefixed with an underscore + eCommandTypesAllThem = 0xFFFF // all commands + }; + + CommandInterpreter(Debugger &debugger, lldb::ScriptLanguage script_language, + bool synchronous_execution); + + ~CommandInterpreter() override; + + // These two functions fill out the Broadcaster interface: + + static ConstString &GetStaticBroadcasterClass(); + + ConstString &GetBroadcasterClass() const override { + return GetStaticBroadcasterClass(); + } + + void SourceInitFile(bool in_cwd, CommandReturnObject &result); + + bool AddCommand(llvm::StringRef name, const lldb::CommandObjectSP &cmd_sp, + bool can_replace); + + bool AddUserCommand(llvm::StringRef name, const lldb::CommandObjectSP &cmd_sp, + bool can_replace); + + lldb::CommandObjectSP GetCommandSPExact(llvm::StringRef cmd, + bool include_aliases) const; + + CommandObject *GetCommandObject(llvm::StringRef cmd, + StringList *matches = nullptr) const; + + bool CommandExists(llvm::StringRef cmd) const; + + bool AliasExists(llvm::StringRef cmd) const; + + bool UserCommandExists(llvm::StringRef cmd) const; + + CommandAlias *AddAlias(llvm::StringRef alias_name, + lldb::CommandObjectSP &command_obj_sp, + llvm::StringRef args_string = llvm::StringRef()); + + // Remove a command if it is removable (python or regex command) + bool RemoveCommand(llvm::StringRef cmd); + + bool RemoveAlias(llvm::StringRef alias_name); + + bool GetAliasFullName(llvm::StringRef cmd, std::string &full_name) const; + + bool RemoveUser(llvm::StringRef alias_name); + + void RemoveAllUser() { m_user_dict.clear(); } + + const CommandAlias *GetAlias(llvm::StringRef alias_name) const; + + CommandObject *BuildAliasResult(llvm::StringRef alias_name, + std::string &raw_input_string, + std::string &alias_result, + CommandReturnObject &result); + + bool HandleCommand(const char *command_line, LazyBool add_to_history, + CommandReturnObject &result, + ExecutionContext *override_context = nullptr, + bool repeat_on_empty_command = true, + bool no_context_switching = false); + + //------------------------------------------------------------------ + /// Execute a list of commands in sequence. + /// + /// @param[in] commands + /// The list of commands to execute. + /// @param[in,out] context + /// The execution context in which to run the commands. Can be nullptr in + /// which case the default + /// context will be used. + /// @param[in] options + /// This object holds the options used to control when to stop, whether to + /// execute commands, + /// etc. + /// @param[out] result + /// This is marked as succeeding with no output if all commands execute + /// safely, + /// and failed with some explanation if we aborted executing the commands + /// at some point. + //------------------------------------------------------------------ + void HandleCommands(const StringList &commands, ExecutionContext *context, + CommandInterpreterRunOptions &options, + CommandReturnObject &result); + + //------------------------------------------------------------------ + /// Execute a list of commands from a file. + /// + /// @param[in] file + /// The file from which to read in commands. + /// @param[in,out] context + /// The execution context in which to run the commands. Can be nullptr in + /// which case the default + /// context will be used. + /// @param[in] options + /// This object holds the options used to control when to stop, whether to + /// execute commands, + /// etc. + /// @param[out] result + /// This is marked as succeeding with no output if all commands execute + /// safely, + /// and failed with some explanation if we aborted executing the commands + /// at some point. + //------------------------------------------------------------------ + void HandleCommandsFromFile(FileSpec &file, ExecutionContext *context, + CommandInterpreterRunOptions &options, + CommandReturnObject &result); + + CommandObject *GetCommandObjectForCommand(llvm::StringRef &command_line); + + // This handles command line completion. You are given a pointer to the + // command string buffer, to the current cursor, + // and to the end of the string (in case it is not NULL terminated). + // You also passed in an StringList object to fill with the returns. + // The first element of the array will be filled with the string that you + // would need to insert at + // the cursor point to complete the cursor point to the longest common + // matching prefix. + // If you want to limit the number of elements returned, set + // max_return_elements to the number of elements + // you want returned. Otherwise set max_return_elements to -1. + // If you want to start some way into the match list, then set + // match_start_point to the desired start + // point. + // Returns: + // -1 if the completion character should be inserted + // -2 if the entire command line should be deleted and replaced with + // matches.GetStringAtIndex(0) + // INT_MAX if the number of matches is > max_return_elements, but it is + // expensive to compute. + // Otherwise, returns the number of matches. + // + // FIXME: Only max_return_elements == -1 is supported at present. + int HandleCompletion(const char *current_line, const char *cursor, + const char *last_char, int match_start_point, + int max_return_elements, StringList &matches); + + // This version just returns matches, and doesn't compute the substring. It + // is here so the + // Help command can call it for the first argument. + // word_complete tells whether the completions are considered a "complete" + // response (so the + // completer should complete the quote & put a space after the word. + int HandleCompletionMatches(Args &input, int &cursor_index, + int &cursor_char_position, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches); + + int GetCommandNamesMatchingPartialString(const char *cmd_cstr, + bool include_aliases, + StringList &matches); + + void GetHelp(CommandReturnObject &result, + uint32_t types = eCommandTypesAllThem); + + void GetAliasHelp(const char *alias_name, StreamString &help_string); + + void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix, + llvm::StringRef help_text); + + void OutputFormattedHelpText(Stream &stream, llvm::StringRef command_word, + llvm::StringRef separator, + llvm::StringRef help_text, size_t max_word_len); + + // this mimics OutputFormattedHelpText but it does perform a much simpler + // formatting, basically ensuring line alignment. This is only good if you + // have some complicated layout for your help text and want as little help as + // reasonable in properly displaying it. Most of the times, you simply want + // to type some text and have it printed in a reasonable way on screen. If + // so, use OutputFormattedHelpText + void OutputHelpText(Stream &stream, llvm::StringRef command_word, + llvm::StringRef separator, llvm::StringRef help_text, + uint32_t max_word_len); + + Debugger &GetDebugger() { return m_debugger; } + + ExecutionContext GetExecutionContext() { + const bool thread_and_frame_only_if_stopped = true; + return m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped); + } + + void UpdateExecutionContext(ExecutionContext *override_context); + + lldb::PlatformSP GetPlatform(bool prefer_target_platform); + + const char *ProcessEmbeddedScriptCommands(const char *arg); + + void UpdatePrompt(llvm::StringRef prompt); + + bool Confirm(llvm::StringRef message, bool default_answer); + + void LoadCommandDictionary(); + + void Initialize(); + + void Clear(); + + void SetScriptLanguage(lldb::ScriptLanguage lang); + + bool HasCommands() const; + + bool HasAliases() const; + + bool HasUserCommands() const; + + bool HasAliasOptions() const; + + void BuildAliasCommandArgs(CommandObject *alias_cmd_obj, + const char *alias_name, Args &cmd_args, + std::string &raw_input_string, + CommandReturnObject &result); + + int GetOptionArgumentPosition(const char *in_string); + + ScriptInterpreter *GetScriptInterpreter(bool can_create = true); + + void SetScriptInterpreter(); + + void SkipLLDBInitFiles(bool skip_lldbinit_files) { + m_skip_lldbinit_files = skip_lldbinit_files; + } + + void SkipAppInitFiles(bool skip_app_init_files) { + m_skip_app_init_files = m_skip_lldbinit_files; + } + + bool GetSynchronous(); + + void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found, + StringList &commands_help, + bool search_builtin_commands, + bool search_user_commands, + bool search_alias_commands); + + bool GetBatchCommandMode() { return m_batch_command_mode; } + + bool SetBatchCommandMode(bool value) { + const bool old_value = m_batch_command_mode; + m_batch_command_mode = value; + return old_value; + } + + void ChildrenTruncated() { + if (m_truncation_warning == eNoTruncation) + m_truncation_warning = eUnwarnedTruncation; + } + + bool TruncationWarningNecessary() { + return (m_truncation_warning == eUnwarnedTruncation); + } + + void TruncationWarningGiven() { m_truncation_warning = eWarnedTruncation; } + + const char *TruncationWarningText() { + return "*** Some of your variables have more members than the debugger " + "will show by default. To show all of them, you can either use the " + "--show-all-children option to %s or raise the limit by changing " + "the target.max-children-count setting.\n"; + } + + const CommandHistory &GetCommandHistory() const { return m_command_history; } + + CommandHistory &GetCommandHistory() { return m_command_history; } + + bool IsActive(); + + void RunCommandInterpreter(bool auto_handle_events, bool spawn_thread, + CommandInterpreterRunOptions &options); + void GetLLDBCommandsFromIOHandler(const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, void *baton); + + void GetPythonCommandsFromIOHandler(const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, void *baton); + + const char *GetCommandPrefix(); + + //------------------------------------------------------------------ + // Properties + //------------------------------------------------------------------ + bool GetExpandRegexAliases() const; + + bool GetPromptOnQuit() const; + + void SetPromptOnQuit(bool b); + + void ResolveCommand(const char *command_line, CommandReturnObject &result); + + bool GetStopCmdSourceOnError() const; + + uint32_t GetNumErrors() const { return m_num_errors; } + + bool GetQuitRequested() const { return m_quit_requested; } + + lldb::IOHandlerSP + GetIOHandler(bool force_create = false, + CommandInterpreterRunOptions *options = nullptr); + + bool GetStoppedForCrash() const { return m_stopped_for_crash; } + + bool GetSpaceReplPrompts() const; + +protected: + friend class Debugger; + + //------------------------------------------------------------------ + // IOHandlerDelegate functions + //------------------------------------------------------------------ + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &line) override; + + ConstString IOHandlerGetControlSequence(char ch) override { + if (ch == 'd') + return ConstString("quit\n"); + return ConstString(); + } + + bool IOHandlerInterrupt(IOHandler &io_handler) override; + + size_t GetProcessOutput(); + + void SetSynchronous(bool value); + + lldb::CommandObjectSP GetCommandSP(llvm::StringRef cmd, + bool include_aliases = true, + bool exact = true, + StringList *matches = nullptr) const; + +private: + Status PreprocessCommand(std::string &command); + + // Completely resolves aliases and abbreviations, returning a pointer to the + // final command object and updating command_line to the fully substituted + // and translated command. + CommandObject *ResolveCommandImpl(std::string &command_line, + CommandReturnObject &result); + + void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found, + StringList &commands_help, + CommandObject::CommandMap &command_map); + + Debugger &m_debugger; // The debugger session that this interpreter is + // associated with + ExecutionContextRef m_exe_ctx_ref; // The current execution context to use + // when handling commands + bool m_synchronous_execution; + bool m_skip_lldbinit_files; + bool m_skip_app_init_files; + CommandObject::CommandMap m_command_dict; // Stores basic built-in commands + // (they cannot be deleted, removed + // or overwritten). + CommandObject::CommandMap + m_alias_dict; // Stores user aliases/abbreviations for commands + CommandObject::CommandMap m_user_dict; // Stores user-defined commands + CommandHistory m_command_history; + std::string m_repeat_command; // Stores the command that will be executed for + // an empty command string. + lldb::ScriptInterpreterSP m_script_interpreter_sp; + std::recursive_mutex m_script_interpreter_mutex; + lldb::IOHandlerSP m_command_io_handler_sp; + char m_comment_char; + bool m_batch_command_mode; + ChildrenTruncatedWarningStatus m_truncation_warning; // Whether we truncated + // children and whether + // the user has been told + uint32_t m_command_source_depth; + std::vector m_command_source_flags; + uint32_t m_num_errors; + bool m_quit_requested; + bool m_stopped_for_crash; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandInterpreter_h_ diff --git a/include/lldb/Interpreter/CommandObject.h b/include/lldb/Interpreter/CommandObject.h new file mode 100644 index 000000000..ff4c829e5 --- /dev/null +++ b/include/lldb/Interpreter/CommandObject.h @@ -0,0 +1,502 @@ +//===-- 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_ + +// C Includes +// C++ Includes +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Flags.h" + +#include "lldb/Interpreter/Args.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/StringList.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +// 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. + +template +int AddNamesMatchingPartialString(const std::map &in_map, + llvm::StringRef cmd_str, StringList &matches) { + int number_added = 0; + + const bool add_all = cmd_str.empty(); + + for (auto iter = in_map.begin(), end = in_map.end(); iter != end; iter++) { + if (add_all || (iter->first.find(cmd_str, 0) == 0)) { + ++number_added; + matches.AppendString(iter->first.c_str()); + } + } + + return number_added; +} + +template +size_t FindLongestCommandWord(std::map &dict) { + auto end = dict.end(); + size_t max_len = 0; + + for (auto pos = dict.begin(); pos != end; ++pos) { + size_t len = pos->first.size(); + if (max_len < len) + max_len = len; + } + return max_len; +} + +class CommandObject { +public: + typedef llvm::StringRef(ArgumentHelpCallbackFunction)(); + + struct ArgumentHelpCallback { + ArgumentHelpCallbackFunction *help_callback; + bool self_formatting; + + llvm::StringRef operator()() const { return (*help_callback)(); } + + explicit operator bool() const { return (help_callback != nullptr); } + }; + + struct ArgumentTableEntry // Entries in the main argument information table + { + lldb::CommandArgumentType arg_type; + const char *arg_name; + CommandCompletions::CommonCompletionTypes completion_type; + ArgumentHelpCallback help_function; + const char *help_text; + }; + + struct CommandArgumentData // Used to build individual command argument lists + { + lldb::CommandArgumentType arg_type; + ArgumentRepetitionType arg_repetition; + uint32_t arg_opt_set_association; // This arg might be associated only with + // some particular option set(s). + CommandArgumentData() + : arg_type(lldb::eArgTypeNone), arg_repetition(eArgRepeatPlain), + arg_opt_set_association(LLDB_OPT_SET_ALL) // By default, the arg + // associates to all option + // sets. + {} + }; + + typedef std::vector + CommandArgumentEntry; // Used to build individual command argument lists + + static ArgumentTableEntry g_arguments_data + [lldb::eArgTypeLastArg]; // Main argument information table + + typedef std::map CommandMap; + + CommandObject(CommandInterpreter &interpreter, llvm::StringRef name, + llvm::StringRef help = "", llvm::StringRef syntax = "", + uint32_t flags = 0); + + virtual ~CommandObject(); + + static const char * + GetArgumentTypeAsCString(const lldb::CommandArgumentType arg_type); + + static const char * + GetArgumentDescriptionAsCString(const lldb::CommandArgumentType arg_type); + + CommandInterpreter &GetCommandInterpreter() { return m_interpreter; } + + virtual llvm::StringRef GetHelp(); + + virtual llvm::StringRef GetHelpLong(); + + virtual llvm::StringRef GetSyntax(); + + llvm::StringRef GetCommandName() const; + + virtual void SetHelp(llvm::StringRef str); + + virtual void SetHelpLong(llvm::StringRef str); + + void SetSyntax(llvm::StringRef str); + + // override this to return true if you want to enable the user to delete + // the Command object from the Command dictionary (aliases have their own + // deletion scheme, so they do not need to care about this) + virtual bool IsRemovable() const { return false; } + + virtual bool IsMultiwordObject() { return false; } + + virtual CommandObjectMultiword *GetAsMultiwordCommand() { return nullptr; } + + virtual bool IsAlias() { return false; } + + // override this to return true if your command is somehow a "dash-dash" + // form of some other command (e.g. po is expr -O --); this is a powerful + // hint to the help system that one cannot pass options to this command + virtual bool IsDashDashCommand() { return false; } + + virtual lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, + StringList *matches = nullptr) { + return lldb::CommandObjectSP(); + } + + virtual CommandObject *GetSubcommandObject(llvm::StringRef sub_cmd, + StringList *matches = nullptr) { + return nullptr; + } + + virtual void AproposAllSubCommands(llvm::StringRef prefix, + llvm::StringRef search_word, + StringList &commands_found, + StringList &commands_help) {} + + void FormatLongHelpText(Stream &output_strm, llvm::StringRef long_help); + + void GenerateHelpText(CommandReturnObject &result); + + virtual void GenerateHelpText(Stream &result); + + // this is needed in order to allow the SBCommand class to + // transparently try and load subcommands - it will fail on + // anything but a multiword command, but it avoids us doing + // type checkings and casts + virtual bool LoadSubCommand(llvm::StringRef cmd_name, + const lldb::CommandObjectSP &command_obj) { + return false; + } + + virtual bool WantsRawCommandString() = 0; + + // By default, WantsCompletion = !WantsRawCommandString. + // Subclasses who want raw command string but desire, for example, + // argument completion should override this method to return true. + virtual bool WantsCompletion() { return !WantsRawCommandString(); } + + virtual Options *GetOptions(); + + static const ArgumentTableEntry *GetArgumentTable(); + + static lldb::CommandArgumentType LookupArgumentName(llvm::StringRef arg_name); + + static const ArgumentTableEntry * + FindArgumentDataByType(lldb::CommandArgumentType arg_type); + + int GetNumArgumentEntries(); + + CommandArgumentEntry *GetArgumentEntryAtIndex(int idx); + + static void GetArgumentHelp(Stream &str, lldb::CommandArgumentType arg_type, + CommandInterpreter &interpreter); + + static const char *GetArgumentName(lldb::CommandArgumentType arg_type); + + // Generates a nicely formatted command args string for help command output. + // By default, all possible args are taken into account, for example, + // ''. This can be refined by passing a second arg + // specifying which option set(s) we are interested, which could then, for + // example, produce either '' or ''. + void GetFormattedCommandArguments(Stream &str, + uint32_t opt_set_mask = LLDB_OPT_SET_ALL); + + bool IsPairType(ArgumentRepetitionType arg_repeat_type); + + bool ParseOptions(Args &args, CommandReturnObject &result); + + void SetCommandName(llvm::StringRef name); + + //------------------------------------------------------------------ + /// The input array contains a parsed version of the line. The insertion + /// point is given by cursor_index (the index in input of the word containing + /// the cursor) and cursor_char_position (the position of the cursor in that + /// word.) + /// This default version handles calling option argument completions and then + /// calls + /// HandleArgumentCompletion if the cursor is on an argument, not an option. + /// Don't override this method, override HandleArgumentCompletion instead + /// unless + /// you have special reasons. + /// + /// @param[in] interpreter + /// The command interpreter doing the completion. + /// + /// @param[in] input + /// The command line parsed into words + /// + /// @param[in] cursor_index + /// The index in \ainput of the word in which the cursor lies. + /// + /// @param[in] cursor_char_pos + /// The character position of the cursor in its argument word. + /// + /// @param[in] match_start_point + /// @param[in] match_return_elements + /// FIXME: Not yet implemented... If there is a match that is expensive + /// to compute, these are + /// here to allow you to compute the completions in batches. Start the + /// completion from \amatch_start_point, + /// and return \amatch_return_elements elements. + /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be inserted + /// after the + /// completion.) \bfalse otherwise. + /// + /// @param[out] matches + /// The array of matches returned. + /// + /// FIXME: This is the wrong return value, since we also need to make a + /// distinction between + /// total number of matches, and the window the user wants returned. + /// + /// @return + /// \btrue if we were in an option, \bfalse otherwise. + //------------------------------------------------------------------ + virtual int HandleCompletion(Args &input, int &cursor_index, + int &cursor_char_position, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches); + + //------------------------------------------------------------------ + /// The input array contains a parsed version of the line. The insertion + /// point is given by cursor_index (the index in input of the word containing + /// the cursor) and cursor_char_position (the position of the cursor in that + /// word.) + /// We've constructed the map of options and their arguments as well if that + /// is + /// helpful for the completion. + /// + /// @param[in] interpreter + /// The command interpreter doing the completion. + /// + /// @param[in] input + /// The command line parsed into words + /// + /// @param[in] cursor_index + /// The index in \ainput of the word in which the cursor lies. + /// + /// @param[in] cursor_char_pos + /// The character position of the cursor in its argument word. + /// + /// @param[in] opt_element_vector + /// The results of the options parse of \a input. + /// + /// @param[in] match_start_point + /// @param[in] match_return_elements + /// See CommandObject::HandleCompletions for a description of how these + /// work. + /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be inserted + /// after the + /// completion.) \bfalse otherwise. + /// + /// @param[out] matches + /// The array of matches returned. + /// + /// FIXME: This is the wrong return value, since we also need to make a + /// distinction between + /// total number of matches, and the window the user wants returned. + /// + /// @return + /// The number of completions. + //------------------------------------------------------------------ + virtual int HandleArgumentCompletion( + Args &input, int &cursor_index, int &cursor_char_position, + OptionElementVector &opt_element_vector, int match_start_point, + int max_return_elements, bool &word_complete, StringList &matches) { + return 0; + } + + bool HelpTextContainsWord(llvm::StringRef search_word, + bool search_short_help = true, + bool search_long_help = true, + bool search_syntax = true, + bool search_options = true); + + //------------------------------------------------------------------ + /// The flags accessor. + /// + /// @return + /// A reference to the Flags member variable. + //------------------------------------------------------------------ + Flags &GetFlags() { return m_flags; } + + //------------------------------------------------------------------ + /// The flags const accessor. + /// + /// @return + /// A const reference to the Flags member variable. + //------------------------------------------------------------------ + const Flags &GetFlags() const { return m_flags; } + + //------------------------------------------------------------------ + /// Get the command that appropriate for a "repeat" of the current command. + /// + /// @param[in] current_command_line + /// The complete current command line. + /// + /// @return + /// nullptr if there is no special repeat command - it will use the + /// current command line. + /// Otherwise a pointer to the command to be repeated. + /// If the returned string is the empty string, the command won't be + /// repeated. + //------------------------------------------------------------------ + virtual const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) { + return nullptr; + } + + bool HasOverrideCallback() const { + return m_command_override_callback || + m_deprecated_command_override_callback; + } + + void SetOverrideCallback(lldb::CommandOverrideCallback callback, + void *baton) { + m_deprecated_command_override_callback = callback; + m_command_override_baton = baton; + } + + void SetOverrideCallback(lldb::CommandOverrideCallbackWithResult callback, + void *baton) { + m_command_override_callback = callback; + m_command_override_baton = baton; + } + + bool InvokeOverrideCallback(const char **argv, CommandReturnObject &result) { + if (m_command_override_callback) + return m_command_override_callback(m_command_override_baton, argv, + result); + else if (m_deprecated_command_override_callback) + return m_deprecated_command_override_callback(m_command_override_baton, + argv); + else + return false; + } + + virtual bool Execute(const char *args_string, + CommandReturnObject &result) = 0; + +protected: + virtual const char *GetInvalidTargetDescription() { + return "invalid target, create a target using the 'target create' command"; + } + + virtual const char *GetInvalidProcessDescription() { + return "invalid process"; + } + + virtual const char *GetInvalidThreadDescription() { return "invalid thread"; } + + virtual const char *GetInvalidFrameDescription() { return "invalid frame"; } + + virtual const char *GetInvalidRegContextDescription() { + return "invalid frame, no registers"; + } + + // This is for use in the command interpreter, when you either want the + // selected target, or if no target + // is present you want to prime the dummy target with entities that will be + // copied over to new targets. + Target *GetSelectedOrDummyTarget(bool prefer_dummy = false); + Target *GetDummyTarget(); + + // If a command needs to use the "current" thread, use this call. + // Command objects will have an ExecutionContext to use, and that may or may + // not have a thread in it. If it + // does, you should use that by default, if not, then use the + // ExecutionContext's target's selected thread, etc... + // This call insulates you from the details of this calculation. + Thread *GetDefaultThread(); + + //------------------------------------------------------------------ + /// Check the command to make sure anything required by this + /// command is available. + /// + /// @param[out] result + /// A command result object, if it is not okay to run the command + /// this will be filled in with a suitable error. + /// + /// @return + /// \b true if it is okay to run this command, \b false otherwise. + //------------------------------------------------------------------ + bool CheckRequirements(CommandReturnObject &result); + + void Cleanup(); + + CommandInterpreter &m_interpreter; + ExecutionContext m_exe_ctx; + std::unique_lock m_api_locker; + std::string m_cmd_name; + std::string m_cmd_help_short; + std::string m_cmd_help_long; + std::string m_cmd_syntax; + Flags m_flags; + std::vector m_arguments; + lldb::CommandOverrideCallback m_deprecated_command_override_callback; + lldb::CommandOverrideCallbackWithResult m_command_override_callback; + void *m_command_override_baton; + + // Helper function to populate IDs or ID ranges as the command argument data + // to the specified command argument entry. + static void AddIDsArgumentData(CommandArgumentEntry &arg, + lldb::CommandArgumentType ID, + lldb::CommandArgumentType IDRange); +}; + +class CommandObjectParsed : public CommandObject { +public: + CommandObjectParsed(CommandInterpreter &interpreter, const char *name, + const char *help = nullptr, const char *syntax = nullptr, + uint32_t flags = 0) + : CommandObject(interpreter, name, help, syntax, flags) {} + + ~CommandObjectParsed() override = default; + + bool Execute(const char *args_string, CommandReturnObject &result) override; + +protected: + virtual bool DoExecute(Args &command, CommandReturnObject &result) = 0; + + bool WantsRawCommandString() override { return false; } +}; + +class CommandObjectRaw : public CommandObject { +public: + CommandObjectRaw(CommandInterpreter &interpreter, llvm::StringRef name, + llvm::StringRef help = "", llvm::StringRef syntax = "", + uint32_t flags = 0) + : CommandObject(interpreter, name, help, syntax, flags) {} + + ~CommandObjectRaw() override = default; + + bool Execute(const char *args_string, CommandReturnObject &result) override; + +protected: + virtual bool DoExecute(const char *command, CommandReturnObject &result) = 0; + + bool WantsRawCommandString() override { return true; } +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObject_h_ diff --git a/include/lldb/Interpreter/CommandObjectMultiword.h b/include/lldb/Interpreter/CommandObjectMultiword.h new file mode 100644 index 000000000..947272f42 --- /dev/null +++ b/include/lldb/Interpreter/CommandObjectMultiword.h @@ -0,0 +1,149 @@ +//===-- 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 +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiword +//------------------------------------------------------------------------- + +class CommandObjectMultiword : public CommandObject { + // These two want to iterate over the subcommand dictionary. + friend class CommandInterpreter; + friend class CommandObjectSyntax; + +public: + CommandObjectMultiword(CommandInterpreter &interpreter, const char *name, + const char *help = nullptr, + const char *syntax = nullptr, uint32_t flags = 0); + + ~CommandObjectMultiword() override; + + bool IsMultiwordObject() override { return true; } + + CommandObjectMultiword *GetAsMultiwordCommand() override { return this; } + + bool LoadSubCommand(llvm::StringRef cmd_name, + const lldb::CommandObjectSP &command_obj) override; + + void GenerateHelpText(Stream &output_stream) override; + + lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, + StringList *matches = nullptr) override; + + CommandObject *GetSubcommandObject(llvm::StringRef sub_cmd, + StringList *matches = nullptr) override; + + void AproposAllSubCommands(llvm::StringRef prefix, + llvm::StringRef search_word, + StringList &commands_found, + StringList &commands_help) override; + + bool WantsRawCommandString() override { return false; } + + int HandleCompletion(Args &input, int &cursor_index, + int &cursor_char_position, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches) override; + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override; + + bool Execute(const char *args_string, CommandReturnObject &result) override; + + bool IsRemovable() const override { return m_can_be_removed; } + + void SetRemovable(bool removable) { m_can_be_removed = removable; } + +protected: + CommandObject::CommandMap &GetSubcommandDictionary() { + return m_subcommand_dict; + } + + CommandObject::CommandMap m_subcommand_dict; + bool m_can_be_removed; +}; + +class CommandObjectProxy : public CommandObject { +public: + CommandObjectProxy(CommandInterpreter &interpreter, const char *name, + const char *help = nullptr, const char *syntax = nullptr, + uint32_t flags = 0); + + ~CommandObjectProxy() override; + + // Subclasses must provide a command object that will be transparently + // used for this object. + virtual CommandObject *GetProxyCommandObject() = 0; + + llvm::StringRef GetHelpLong() override; + + bool IsRemovable() const override; + + bool IsMultiwordObject() override; + + CommandObjectMultiword *GetAsMultiwordCommand() override; + + void GenerateHelpText(Stream &result) override; + + lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd, + StringList *matches = nullptr) override; + + CommandObject *GetSubcommandObject(llvm::StringRef sub_cmd, + StringList *matches = nullptr) override; + + void AproposAllSubCommands(llvm::StringRef prefix, + llvm::StringRef search_word, + StringList &commands_found, + StringList &commands_help) override; + + bool LoadSubCommand(llvm::StringRef cmd_name, + const lldb::CommandObjectSP &command_obj) override; + + bool WantsRawCommandString() override; + + bool WantsCompletion() override; + + Options *GetOptions() override; + + int HandleCompletion(Args &input, int &cursor_index, + int &cursor_char_position, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches) override; + + int HandleArgumentCompletion(Args &input, int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, int max_return_elements, + bool &word_complete, + StringList &matches) override; + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override; + + bool Execute(const char *args_string, CommandReturnObject &result) override; + +protected: + // These two want to iterate over the subcommand dictionary. + friend class CommandInterpreter; + friend class CommandObjectSyntax; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectMultiword_h_ diff --git a/include/lldb/Interpreter/CommandObjectRegexCommand.h b/include/lldb/Interpreter/CommandObjectRegexCommand.h new file mode 100644 index 000000000..50dbebc21 --- /dev/null +++ b/include/lldb/Interpreter/CommandObjectRegexCommand.h @@ -0,0 +1,68 @@ +//===-- 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 + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Utility/RegularExpression.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectRegexCommand +//------------------------------------------------------------------------- + +class CommandObjectRegexCommand : public CommandObjectRaw { +public: + CommandObjectRegexCommand(CommandInterpreter &interpreter, llvm::StringRef name, + llvm::StringRef help, llvm::StringRef syntax, + uint32_t max_matches, uint32_t completion_type_mask, + bool is_removable); + + ~CommandObjectRegexCommand() override; + + bool IsRemovable() const override { return m_is_removable; } + + bool AddRegexCommand(const char *re_cstr, const char *command_cstr); + + bool HasRegexEntries() const { return !m_entries.empty(); } + + int HandleCompletion(Args &input, int &cursor_index, + int &cursor_char_position, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches) override; + +protected: + bool DoExecute(const char *command, CommandReturnObject &result) override; + + struct Entry { + RegularExpression regex; + std::string command; + }; + + typedef std::list EntryCollection; + const uint32_t m_max_matches; + const uint32_t m_completion_type_mask; + EntryCollection m_entries; + bool m_is_removable; + +private: + DISALLOW_COPY_AND_ASSIGN(CommandObjectRegexCommand); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectRegexCommand_h_ diff --git a/include/lldb/Interpreter/CommandOptionValidators.h b/include/lldb/Interpreter/CommandOptionValidators.h new file mode 100644 index 000000000..05724cace --- /dev/null +++ b/include/lldb/Interpreter/CommandOptionValidators.h @@ -0,0 +1,33 @@ +//===-- CommandOptionValidators.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandOptionValidators_h_ +#define liblldb_CommandOptionValidators_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private-types.h" + +namespace lldb_private { + +class Platform; +class ExecutionContext; + +class PosixPlatformCommandOptionValidator : public OptionValidator { + bool IsValid(Platform &platform, + const ExecutionContext &target) const override; + const char *ShortConditionString() const override; + const char *LongConditionString() const override; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandOptionValidators_h_ diff --git a/include/lldb/Interpreter/CommandReturnObject.h b/include/lldb/Interpreter/CommandReturnObject.h new file mode 100644 index 000000000..7b04c391b --- /dev/null +++ b/include/lldb/Interpreter/CommandReturnObject.h @@ -0,0 +1,182 @@ +//===-- 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/Core/STLUtils.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/StreamTee.h" +#include "lldb/lldb-private.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" + +#include + +namespace lldb_private { + +class CommandReturnObject { +public: + CommandReturnObject(); + + ~CommandReturnObject(); + + llvm::StringRef GetOutputData() { + lldb::StreamSP stream_sp(m_out_stream.GetStreamAtIndex(eStreamStringIndex)); + if (stream_sp) + return static_pointer_cast(stream_sp)->GetString(); + return llvm::StringRef(); + } + + llvm::StringRef GetErrorData() { + lldb::StreamSP stream_sp(m_err_stream.GetStreamAtIndex(eStreamStringIndex)); + if (stream_sp) + return static_pointer_cast(stream_sp)->GetString(); + return llvm::StringRef(); + } + + Stream &GetOutputStream() { + // Make sure we at least have our normal string stream output stream + lldb::StreamSP stream_sp(m_out_stream.GetStreamAtIndex(eStreamStringIndex)); + if (!stream_sp) { + stream_sp.reset(new StreamString()); + m_out_stream.SetStreamAtIndex(eStreamStringIndex, stream_sp); + } + return m_out_stream; + } + + Stream &GetErrorStream() { + // Make sure we at least have our normal string stream output stream + lldb::StreamSP stream_sp(m_err_stream.GetStreamAtIndex(eStreamStringIndex)); + if (!stream_sp) { + stream_sp.reset(new StreamString()); + m_err_stream.SetStreamAtIndex(eStreamStringIndex, stream_sp); + } + return m_err_stream; + } + + void SetImmediateOutputFile(FILE *fh, bool transfer_fh_ownership = false) { + lldb::StreamSP stream_sp(new StreamFile(fh, transfer_fh_ownership)); + m_out_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); + } + + void SetImmediateErrorFile(FILE *fh, bool transfer_fh_ownership = false) { + lldb::StreamSP stream_sp(new StreamFile(fh, transfer_fh_ownership)); + m_err_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); + } + + void SetImmediateOutputStream(const lldb::StreamSP &stream_sp) { + m_out_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); + } + + void SetImmediateErrorStream(const lldb::StreamSP &stream_sp) { + m_err_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); + } + + lldb::StreamSP GetImmediateOutputStream() { + return m_out_stream.GetStreamAtIndex(eImmediateStreamIndex); + } + + lldb::StreamSP GetImmediateErrorStream() { + return m_err_stream.GetStreamAtIndex(eImmediateStreamIndex); + } + + void Clear(); + + void AppendMessage(llvm::StringRef in_string); + + void AppendMessageWithFormat(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + void AppendRawWarning(llvm::StringRef in_string); + + void AppendWarning(llvm::StringRef in_string); + + void AppendWarningWithFormat(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + void AppendError(llvm::StringRef in_string); + + void AppendRawError(llvm::StringRef in_string); + + void AppendErrorWithFormat(const char *format, ...) + __attribute__((format(printf, 2, 3))); + + template + void AppendMessageWithFormatv(const char *format, Args &&... args) { + AppendMessage(llvm::formatv(format, std::forward(args)...).str()); + } + + template + void AppendWarningWithFormatv(const char *format, Args &&... args) { + AppendWarning(llvm::formatv(format, std::forward(args)...).str()); + } + + template + void AppendErrorWithFormatv(const char *format, Args &&... args) { + AppendError(llvm::formatv(format, std::forward(args)...).str()); + } + + void SetError(const Status &error, const char *fallback_error_cstr = nullptr); + + void SetError(llvm::StringRef error_cstr); + + lldb::ReturnStatus GetStatus(); + + void SetStatus(lldb::ReturnStatus status); + + bool Succeeded(); + + bool HasResult(); + + bool GetDidChangeProcessState(); + + void SetDidChangeProcessState(bool b); + + bool GetInteractive() const; + + void SetInteractive(bool b); + + bool GetAbnormalStopWasExpected() const { + return m_abnormal_stop_was_expected; + } + + void SetAbnormalStopWasExpected(bool signal_was_expected) { + m_abnormal_stop_was_expected = signal_was_expected; + } + +private: + enum { eStreamStringIndex = 0, eImmediateStreamIndex = 1 }; + + StreamTee m_out_stream; + StreamTee m_err_stream; + + lldb::ReturnStatus m_status; + bool m_did_change_process_state; + bool m_interactive; // If true, then the input handle from the debugger will + // be hooked up + bool m_abnormal_stop_was_expected; // This is to support + // eHandleCommandFlagStopOnCrash vrs. + // attach. + // The attach command often ends up with the process stopped due to a signal. + // Normally that would mean stop on crash should halt batch execution, but we + // obviously don't want that for attach. Using this flag, the attach command + // (and anything else for which this is relevant) can say that the signal is + // expected, and batch command execution can continue. +}; + +} // namespace lldb_private + +#endif // liblldb_CommandReturnObject_h_ diff --git a/include/lldb/Interpreter/OptionGroupArchitecture.h b/include/lldb/Interpreter/OptionGroupArchitecture.h new file mode 100644 index 000000000..e73a53421 --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupArchitecture.h @@ -0,0 +1,52 @@ +//===-- OptionGroupArchitecture.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupArchitecture_h_ +#define liblldb_OptionGroupArchitecture_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupArchitecture +//------------------------------------------------------------------------- + +class OptionGroupArchitecture : public OptionGroup { +public: + OptionGroupArchitecture(); + + ~OptionGroupArchitecture() override; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + bool GetArchitecture(Platform *platform, ArchSpec &arch); + + bool ArchitectureWasSpecified() const { return !m_arch_str.empty(); } + + llvm::StringRef GetArchitectureName() const { return m_arch_str; } + +protected: + std::string m_arch_str; // Save the arch triple in case a platform is + // specified after the architecture +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupArchitecture_h_ diff --git a/include/lldb/Interpreter/OptionGroupBoolean.h b/include/lldb/Interpreter/OptionGroupBoolean.h new file mode 100644 index 000000000..53d08d79d --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupBoolean.h @@ -0,0 +1,58 @@ +//===-- OptionGroupBoolean.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupBoolean_h_ +#define liblldb_OptionGroupBoolean_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { +//------------------------------------------------------------------------- +// OptionGroupBoolean +//------------------------------------------------------------------------- + +class OptionGroupBoolean : public OptionGroup { +public: + // When 'no_argument_toggle_default' is true, then setting the option + // value does NOT require an argument, it sets the boolean value to the + // inverse of the default value + OptionGroupBoolean(uint32_t usage_mask, bool required, + const char *long_option, int short_option, + const char *usage_text, bool default_value, + bool no_argument_toggle_default); + + ~OptionGroupBoolean() override; + + llvm::ArrayRef GetDefinitions() override { + return llvm::ArrayRef(&m_option_definition, 1); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + OptionValueBoolean &GetOptionValue() { return m_value; } + + const OptionValueBoolean &GetOptionValue() const { return m_value; } + +protected: + OptionValueBoolean m_value; + OptionDefinition m_option_definition; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupBoolean_h_ diff --git a/include/lldb/Interpreter/OptionGroupFile.h b/include/lldb/Interpreter/OptionGroupFile.h new file mode 100644 index 000000000..d0c25b8bf --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupFile.h @@ -0,0 +1,90 @@ +//===-- OptionGroupFile.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupFile_h_ +#define liblldb_OptionGroupFile_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueFileSpec.h" +#include "lldb/Interpreter/OptionValueFileSpecList.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupFile +//------------------------------------------------------------------------- + +class OptionGroupFile : public OptionGroup { +public: + OptionGroupFile(uint32_t usage_mask, bool required, const char *long_option, + int short_option, uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text); + + ~OptionGroupFile() override; + + llvm::ArrayRef GetDefinitions() override { + return llvm::ArrayRef(&m_option_definition, 1); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + OptionValueFileSpec &GetOptionValue() { return m_file; } + + const OptionValueFileSpec &GetOptionValue() const { return m_file; } + +protected: + OptionValueFileSpec m_file; + OptionDefinition m_option_definition; +}; + +//------------------------------------------------------------------------- +// OptionGroupFileList +//------------------------------------------------------------------------- + +class OptionGroupFileList : public OptionGroup { +public: + OptionGroupFileList(uint32_t usage_mask, bool required, + const char *long_option, int short_option, + uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text); + + ~OptionGroupFileList() override; + + llvm::ArrayRef GetDefinitions() override { + return llvm::ArrayRef(&m_option_definition, 1); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + OptionValueFileSpecList &GetOptionValue() { return m_file_list; } + + const OptionValueFileSpecList &GetOptionValue() const { return m_file_list; } + +protected: + OptionValueFileSpecList m_file_list; + OptionDefinition m_option_definition; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupFile_h_ diff --git a/include/lldb/Interpreter/OptionGroupFormat.h b/include/lldb/Interpreter/OptionGroupFormat.h new file mode 100644 index 000000000..ddf2ccece --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupFormat.h @@ -0,0 +1,88 @@ +//===-- OptionGroupFormat.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupFormat_h_ +#define liblldb_OptionGroupFormat_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueFormat.h" +#include "lldb/Interpreter/OptionValueSInt64.h" +#include "lldb/Interpreter/OptionValueUInt64.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupFormat +//------------------------------------------------------------------------- + +class OptionGroupFormat : public OptionGroup { +public: + static const uint32_t OPTION_GROUP_FORMAT = LLDB_OPT_SET_1; + static const uint32_t OPTION_GROUP_GDB_FMT = LLDB_OPT_SET_2; + static const uint32_t OPTION_GROUP_SIZE = LLDB_OPT_SET_3; + static const uint32_t OPTION_GROUP_COUNT = LLDB_OPT_SET_4; + + OptionGroupFormat( + lldb::Format default_format, + uint64_t default_byte_size = + UINT64_MAX, // Pass UINT64_MAX to disable the "--size" option + uint64_t default_count = + UINT64_MAX); // Pass UINT64_MAX to disable the "--count" option + + ~OptionGroupFormat() override; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + lldb::Format GetFormat() const { return m_format.GetCurrentValue(); } + + OptionValueFormat &GetFormatValue() { return m_format; } + + const OptionValueFormat &GetFormatValue() const { return m_format; } + + OptionValueUInt64 &GetByteSizeValue() { return m_byte_size; } + + const OptionValueUInt64 &GetByteSizeValue() const { return m_byte_size; } + + OptionValueUInt64 &GetCountValue() { return m_count; } + + const OptionValueUInt64 &GetCountValue() const { return m_count; } + + bool HasGDBFormat() const { return m_has_gdb_format; } + + bool AnyOptionWasSet() const { + return m_format.OptionWasSet() || m_byte_size.OptionWasSet() || + m_count.OptionWasSet(); + } + +protected: + bool ParserGDBFormatLetter(ExecutionContext *execution_context, + char format_letter, lldb::Format &format, + uint32_t &byte_size); + + OptionValueFormat m_format; + OptionValueUInt64 m_byte_size; + OptionValueUInt64 m_count; + char m_prev_gdb_format; + char m_prev_gdb_size; + bool m_has_gdb_format; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupFormat_h_ diff --git a/include/lldb/Interpreter/OptionGroupOutputFile.h b/include/lldb/Interpreter/OptionGroupOutputFile.h new file mode 100644 index 000000000..19453c621 --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupOutputFile.h @@ -0,0 +1,55 @@ +//===-- OptionGroupOutputFile.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupOutputFile_h_ +#define liblldb_OptionGroupOutputFile_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueFileSpec.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { +//------------------------------------------------------------------------- +// OptionGroupOutputFile +//------------------------------------------------------------------------- + +class OptionGroupOutputFile : public OptionGroup { +public: + OptionGroupOutputFile(); + + ~OptionGroupOutputFile() override; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + const OptionValueFileSpec &GetFile() { return m_file; } + + const OptionValueBoolean &GetAppend() { return m_append; } + + bool AnyOptionWasSet() const { + return m_file.OptionWasSet() || m_append.OptionWasSet(); + } + +protected: + OptionValueFileSpec m_file; + OptionValueBoolean m_append; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupOutputFile_h_ diff --git a/include/lldb/Interpreter/OptionGroupPlatform.h b/include/lldb/Interpreter/OptionGroupPlatform.h new file mode 100644 index 000000000..e79662400 --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupPlatform.h @@ -0,0 +1,83 @@ +//===-- OptionGroupPlatform.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupPlatform_h_ +#define liblldb_OptionGroupPlatform_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/Options.h" +#include "lldb/Utility/ConstString.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// PlatformOptionGroup +// +// Make platform options available to any commands that need the settings. +//------------------------------------------------------------------------- +class OptionGroupPlatform : public OptionGroup { +public: + OptionGroupPlatform(bool include_platform_option) + : OptionGroup(), m_platform_name(), m_sdk_sysroot(), + m_os_version_major(UINT32_MAX), m_os_version_minor(UINT32_MAX), + m_os_version_update(UINT32_MAX), + m_include_platform_option(include_platform_option) {} + + ~OptionGroupPlatform() override = default; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + lldb::PlatformSP CreatePlatformWithOptions(CommandInterpreter &interpreter, + const ArchSpec &arch, + bool make_selected, Status &error, + ArchSpec &platform_arch) const; + + bool PlatformWasSpecified() const { return !m_platform_name.empty(); } + + void SetPlatformName(const char *platform_name) { + if (platform_name && platform_name[0]) + m_platform_name.assign(platform_name); + else + m_platform_name.clear(); + } + + const ConstString &GetSDKRootDirectory() const { return m_sdk_sysroot; } + + void SetSDKRootDirectory(const ConstString &sdk_root_directory) { + m_sdk_sysroot = sdk_root_directory; + } + + const ConstString &GetSDKBuild() const { return m_sdk_build; } + + void SetSDKBuild(const ConstString &sdk_build) { m_sdk_build = sdk_build; } + + bool PlatformMatches(const lldb::PlatformSP &platform_sp) const; + +protected: + std::string m_platform_name; + ConstString m_sdk_sysroot; + ConstString m_sdk_build; + uint32_t m_os_version_major; + uint32_t m_os_version_minor; + uint32_t m_os_version_update; + bool m_include_platform_option; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupPlatform_h_ diff --git a/include/lldb/Interpreter/OptionGroupString.h b/include/lldb/Interpreter/OptionGroupString.h new file mode 100644 index 000000000..01e8aa9dc --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupString.h @@ -0,0 +1,55 @@ +//===-- OptionGroupString.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupString_h_ +#define liblldb_OptionGroupString_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { +//------------------------------------------------------------------------- +// OptionGroupString +//------------------------------------------------------------------------- + +class OptionGroupString : public OptionGroup { +public: + OptionGroupString(uint32_t usage_mask, bool required, const char *long_option, + int short_option, uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text, const char *default_value); + + ~OptionGroupString() override; + + llvm::ArrayRef GetDefinitions() override { + return llvm::ArrayRef(&m_option_definition, 1); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + OptionValueString &GetOptionValue() { return m_value; } + + const OptionValueString &GetOptionValue() const { return m_value; } + +protected: + OptionValueString m_value; + OptionDefinition m_option_definition; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupString_h_ diff --git a/include/lldb/Interpreter/OptionGroupUInt64.h b/include/lldb/Interpreter/OptionGroupUInt64.h new file mode 100644 index 000000000..82eb0e26a --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupUInt64.h @@ -0,0 +1,56 @@ +//===-- OptionGroupUInt64.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupUInt64_h_ +#define liblldb_OptionGroupUInt64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueUInt64.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupUInt64 +//------------------------------------------------------------------------- + +class OptionGroupUInt64 : public OptionGroup { +public: + OptionGroupUInt64(uint32_t usage_mask, bool required, const char *long_option, + int short_option, uint32_t completion_type, + lldb::CommandArgumentType argument_type, + const char *usage_text, uint64_t default_value); + + ~OptionGroupUInt64() override; + + llvm::ArrayRef GetDefinitions() override { + return llvm::ArrayRef(&m_option_definition, 1); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + OptionValueUInt64 &GetOptionValue() { return m_value; } + + const OptionValueUInt64 &GetOptionValue() const { return m_value; } + +protected: + OptionValueUInt64 m_value; + OptionDefinition m_option_definition; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupUInt64_h_ diff --git a/include/lldb/Interpreter/OptionGroupUUID.h b/include/lldb/Interpreter/OptionGroupUUID.h new file mode 100644 index 000000000..def97d5f2 --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupUUID.h @@ -0,0 +1,48 @@ +//===-- OptionGroupUUID.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupUUID_h_ +#define liblldb_OptionGroupUUID_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueUUID.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupUUID +//------------------------------------------------------------------------- + +class OptionGroupUUID : public OptionGroup { +public: + OptionGroupUUID(); + + ~OptionGroupUUID() override; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + const OptionValueUUID &GetOptionValue() const { return m_uuid; } + +protected: + OptionValueUUID m_uuid; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupUUID_h_ diff --git a/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h new file mode 100644 index 000000000..0e075773b --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h @@ -0,0 +1,65 @@ +//===-- OptionGroupValueObjectDisplay.h -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupValueObjectDisplay_h_ +#define liblldb_OptionGroupValueObjectDisplay_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ValueObject.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupValueObjectDisplay +//------------------------------------------------------------------------- + +class OptionGroupValueObjectDisplay : public OptionGroup { +public: + OptionGroupValueObjectDisplay(); + + ~OptionGroupValueObjectDisplay() override; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + bool AnyOptionWasSet() const { + return show_types || no_summary_depth != 0 || show_location || + flat_output || use_objc || max_depth != UINT32_MAX || + ptr_depth != 0 || !use_synth || be_raw || ignore_cap || + run_validator; + } + + DumpValueObjectOptions GetAsDumpOptions( + LanguageRuntimeDescriptionDisplayVerbosity lang_descr_verbosity = + eLanguageRuntimeDescriptionDisplayVerbosityFull, + lldb::Format format = lldb::eFormatDefault, + lldb::TypeSummaryImplSP summary_sp = lldb::TypeSummaryImplSP()); + + bool show_types : 1, show_location : 1, flat_output : 1, use_objc : 1, + use_synth : 1, be_raw : 1, ignore_cap : 1, run_validator : 1; + + uint32_t no_summary_depth; + uint32_t max_depth; + uint32_t ptr_depth; + uint32_t elem_count; + lldb::DynamicValueType use_dynamic; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupValueObjectDisplay_h_ diff --git a/include/lldb/Interpreter/OptionGroupVariable.h b/include/lldb/Interpreter/OptionGroupVariable.h new file mode 100644 index 000000000..c9e90320e --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupVariable.h @@ -0,0 +1,54 @@ +//===-- OptionGroupVariable.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupVariable_h_ +#define liblldb_OptionGroupVariable_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupVariable +//------------------------------------------------------------------------- + +class OptionGroupVariable : public OptionGroup { +public: + OptionGroupVariable(bool show_frame_options); + + ~OptionGroupVariable() override; + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + bool include_frame_options : 1, + show_args : 1, // Frame option only (include_frame_options == true) + show_locals : 1, // Frame option only (include_frame_options == true) + show_globals : 1, // Frame option only (include_frame_options == true) + use_regex : 1, show_scope : 1, show_decl : 1; + OptionValueString summary; // the name of a named summary + OptionValueString summary_string; // a summary string + +private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupVariable); +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupVariable_h_ diff --git a/include/lldb/Interpreter/OptionGroupWatchpoint.h b/include/lldb/Interpreter/OptionGroupWatchpoint.h new file mode 100644 index 000000000..f2665638b --- /dev/null +++ b/include/lldb/Interpreter/OptionGroupWatchpoint.h @@ -0,0 +1,61 @@ +//===-- OptionGroupWatchpoint.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionGroupWatchpoint_h_ +#define liblldb_OptionGroupWatchpoint_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// OptionGroupWatchpoint +//------------------------------------------------------------------------- + +class OptionGroupWatchpoint : public OptionGroup { +public: + OptionGroupWatchpoint(); + + ~OptionGroupWatchpoint() override; + + static bool IsWatchSizeSupported(uint32_t watch_size); + + llvm::ArrayRef GetDefinitions() override; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + // Note: + // eWatchRead == LLDB_WATCH_TYPE_READ; and + // eWatchWrite == LLDB_WATCH_TYPE_WRITE + typedef enum WatchType { + eWatchInvalid = 0, + eWatchRead, + eWatchWrite, + eWatchReadWrite + } WatchType; + + WatchType watch_type; + uint32_t watch_size; + bool watch_type_specified; + +private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupWatchpoint); +}; + +} // namespace lldb_private + +#endif // liblldb_OptionGroupWatchpoint_h_ diff --git a/include/lldb/Interpreter/OptionValue.h b/include/lldb/Interpreter/OptionValue.h new file mode 100644 index 000000000..6008e1ea4 --- /dev/null +++ b/include/lldb/Interpreter/OptionValue.h @@ -0,0 +1,350 @@ +//===-- OptionValue.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValue_h_ +#define liblldb_OptionValue_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/FormatEntity.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-private-enumerations.h" +#include "lldb/lldb-private-interfaces.h" + +namespace lldb_private { + +//--------------------------------------------------------------------- +// OptionValue +//--------------------------------------------------------------------- +class OptionValue { +public: + typedef enum { + eTypeInvalid = 0, + eTypeArch, + eTypeArgs, + eTypeArray, + eTypeBoolean, + eTypeChar, + eTypeDictionary, + eTypeEnum, + eTypeFileSpec, + eTypeFileSpecList, + eTypeFormat, + eTypeLanguage, + eTypePathMap, + eTypeProperties, + eTypeRegex, + eTypeSInt64, + eTypeString, + eTypeUInt64, + eTypeUUID, + eTypeFormatEntity + } Type; + + enum { + eDumpOptionName = (1u << 0), + eDumpOptionType = (1u << 1), + eDumpOptionValue = (1u << 2), + eDumpOptionDescription = (1u << 3), + eDumpOptionRaw = (1u << 4), + eDumpGroupValue = (eDumpOptionName | eDumpOptionType | eDumpOptionValue), + eDumpGroupHelp = + (eDumpOptionName | eDumpOptionType | eDumpOptionDescription) + }; + + OptionValue() + : m_callback(nullptr), m_baton(nullptr), m_value_was_set(false) {} + + OptionValue(const OptionValue &rhs) + : m_callback(rhs.m_callback), m_baton(rhs.m_baton), + m_value_was_set(rhs.m_value_was_set) {} + + virtual ~OptionValue() = default; + + //----------------------------------------------------------------- + // Subclasses should override these functions + //----------------------------------------------------------------- + virtual Type GetType() const = 0; + + // If this value is always hidden, the avoid showing any info on this + // value, just show the info for the child values. + virtual bool ValueIsTransparent() const { + return GetType() == eTypeProperties; + } + + virtual const char *GetTypeAsCString() const { + return GetBuiltinTypeAsCString(GetType()); + } + + static const char *GetBuiltinTypeAsCString(Type t); + + virtual void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) = 0; + + virtual Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign); + + virtual bool Clear() = 0; + + virtual lldb::OptionValueSP DeepCopy() const = 0; + + virtual size_t AutoComplete(CommandInterpreter &interpreter, + llvm::StringRef s, int match_start_point, + int max_return_elements, bool &word_complete, + StringList &matches); + + //----------------------------------------------------------------- + // Subclasses can override these functions + //----------------------------------------------------------------- + virtual lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx, + llvm::StringRef name, + bool will_modify, + Status &error) const { + error.SetErrorStringWithFormat("'%s' is not a value subvalue", name.str().c_str()); + return lldb::OptionValueSP(); + } + + virtual Status SetSubValue(const ExecutionContext *exe_ctx, + VarSetOperationType op, llvm::StringRef name, + llvm::StringRef value); + + virtual bool IsAggregateValue() const { return false; } + + virtual ConstString GetName() const { return ConstString(); } + + virtual bool DumpQualifiedName(Stream &strm) const; + + //----------------------------------------------------------------- + // Subclasses should NOT override these functions as they use the + // above functions to implement functionality + //----------------------------------------------------------------- + uint32_t GetTypeAsMask() { return 1u << GetType(); } + + static uint32_t ConvertTypeToMask(OptionValue::Type type) { + return 1u << type; + } + + static OptionValue::Type ConvertTypeMaskToType(uint32_t type_mask) { + // If only one bit is set, then return an appropriate enumeration + switch (type_mask) { + case 1u << eTypeArch: + return eTypeArch; + case 1u << eTypeArgs: + return eTypeArgs; + case 1u << eTypeArray: + return eTypeArray; + case 1u << eTypeBoolean: + return eTypeBoolean; + case 1u << eTypeChar: + return eTypeChar; + case 1u << eTypeDictionary: + return eTypeDictionary; + case 1u << eTypeEnum: + return eTypeEnum; + case 1u << eTypeFileSpec: + return eTypeFileSpec; + case 1u << eTypeFileSpecList: + return eTypeFileSpecList; + case 1u << eTypeFormat: + return eTypeFormat; + case 1u << eTypeLanguage: + return eTypeLanguage; + case 1u << eTypePathMap: + return eTypePathMap; + case 1u << eTypeProperties: + return eTypeProperties; + case 1u << eTypeRegex: + return eTypeRegex; + case 1u << eTypeSInt64: + return eTypeSInt64; + case 1u << eTypeString: + return eTypeString; + case 1u << eTypeUInt64: + return eTypeUInt64; + case 1u << eTypeUUID: + return eTypeUUID; + } + // Else return invalid + return eTypeInvalid; + } + + static lldb::OptionValueSP + CreateValueFromCStringForTypeMask(const char *value_cstr, uint32_t type_mask, + Status &error); + + // Get this value as a uint64_t value if it is encoded as a boolean, + // uint64_t or int64_t. Other types will cause "fail_value" to be + // returned + uint64_t GetUInt64Value(uint64_t fail_value, bool *success_ptr); + + OptionValueArch *GetAsArch(); + + const OptionValueArch *GetAsArch() const; + + OptionValueArray *GetAsArray(); + + const OptionValueArray *GetAsArray() const; + + OptionValueArgs *GetAsArgs(); + + const OptionValueArgs *GetAsArgs() const; + + OptionValueBoolean *GetAsBoolean(); + + OptionValueChar *GetAsChar(); + + const OptionValueBoolean *GetAsBoolean() const; + + const OptionValueChar *GetAsChar() const; + + OptionValueDictionary *GetAsDictionary(); + + const OptionValueDictionary *GetAsDictionary() const; + + OptionValueEnumeration *GetAsEnumeration(); + + const OptionValueEnumeration *GetAsEnumeration() const; + + OptionValueFileSpec *GetAsFileSpec(); + + const OptionValueFileSpec *GetAsFileSpec() const; + + OptionValueFileSpecList *GetAsFileSpecList(); + + const OptionValueFileSpecList *GetAsFileSpecList() const; + + OptionValueFormat *GetAsFormat(); + + const OptionValueFormat *GetAsFormat() const; + + OptionValueLanguage *GetAsLanguage(); + + const OptionValueLanguage *GetAsLanguage() const; + + OptionValuePathMappings *GetAsPathMappings(); + + const OptionValuePathMappings *GetAsPathMappings() const; + + OptionValueProperties *GetAsProperties(); + + const OptionValueProperties *GetAsProperties() const; + + OptionValueRegex *GetAsRegex(); + + const OptionValueRegex *GetAsRegex() const; + + OptionValueSInt64 *GetAsSInt64(); + + const OptionValueSInt64 *GetAsSInt64() const; + + OptionValueString *GetAsString(); + + const OptionValueString *GetAsString() const; + + OptionValueUInt64 *GetAsUInt64(); + + const OptionValueUInt64 *GetAsUInt64() const; + + OptionValueUUID *GetAsUUID(); + + const OptionValueUUID *GetAsUUID() const; + + OptionValueFormatEntity *GetAsFormatEntity(); + + const OptionValueFormatEntity *GetAsFormatEntity() const; + + bool GetBooleanValue(bool fail_value = false) const; + + bool SetBooleanValue(bool new_value); + + char GetCharValue(char fail_value) const; + + char SetCharValue(char new_value); + + int64_t GetEnumerationValue(int64_t fail_value = -1) const; + + bool SetEnumerationValue(int64_t value); + + FileSpec GetFileSpecValue() const; + + bool SetFileSpecValue(const FileSpec &file_spec); + + FileSpecList GetFileSpecListValue() const; + + lldb::Format + GetFormatValue(lldb::Format fail_value = lldb::eFormatDefault) const; + + bool SetFormatValue(lldb::Format new_value); + + lldb::LanguageType GetLanguageValue( + lldb::LanguageType fail_value = lldb::eLanguageTypeUnknown) const; + + bool SetLanguageValue(lldb::LanguageType new_language); + + const FormatEntity::Entry *GetFormatEntity() const; + + const RegularExpression *GetRegexValue() const; + + int64_t GetSInt64Value(int64_t fail_value = 0) const; + + bool SetSInt64Value(int64_t new_value); + + llvm::StringRef GetStringValue(llvm::StringRef fail_value) const; + llvm::StringRef GetStringValue() const { return GetStringValue(llvm::StringRef()); } + + bool SetStringValue(llvm::StringRef new_value); + + uint64_t GetUInt64Value(uint64_t fail_value = 0) const; + + bool SetUInt64Value(uint64_t new_value); + + UUID GetUUIDValue() const; + + bool SetUUIDValue(const UUID &uuid); + + bool OptionWasSet() const { return m_value_was_set; } + + void SetOptionWasSet() { m_value_was_set = true; } + + void SetParent(const lldb::OptionValueSP &parent_sp) { + m_parent_wp = parent_sp; + } + + void SetValueChangedCallback(OptionValueChangedCallback callback, + void *baton) { + assert(m_callback == nullptr); + m_callback = callback; + m_baton = baton; + } + + void NotifyValueChanged() { + if (m_callback) + m_callback(m_baton, this); + } + +protected: + lldb::OptionValueWP m_parent_wp; + OptionValueChangedCallback m_callback; + void *m_baton; + bool m_value_was_set; // This can be used to see if a value has been set + // by a call to SetValueFromCString(). It is often + // handy to know if an option value was set from + // the command line or as a setting, versus if we + // just have the default value that was already + // populated in the option value. +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValue_h_ diff --git a/include/lldb/Interpreter/OptionValueArch.h b/include/lldb/Interpreter/OptionValueArch.h new file mode 100644 index 000000000..e1a354d4a --- /dev/null +++ b/include/lldb/Interpreter/OptionValueArch.h @@ -0,0 +1,93 @@ +//===-- OptionValueArch.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueArch_h_ +#define liblldb_OptionValueArch_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueArch : public OptionValue { +public: + OptionValueArch() : OptionValue(), m_current_value(), m_default_value() {} + + OptionValueArch(const char *triple) + : OptionValue(), m_current_value(triple), m_default_value() { + m_default_value = m_current_value; + } + + OptionValueArch(const ArchSpec &value) + : OptionValue(), m_current_value(value), m_default_value(value) {} + + OptionValueArch(const ArchSpec ¤t_value, const ArchSpec &default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value) {} + + ~OptionValueArch() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeArch; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + size_t AutoComplete(CommandInterpreter &interpreter, llvm::StringRef s, + int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + ArchSpec &GetCurrentValue() { return m_current_value; } + + const ArchSpec &GetCurrentValue() const { return m_current_value; } + + const ArchSpec &GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(const ArchSpec &value, bool set_value_was_set) { + m_current_value = value; + if (set_value_was_set) + m_value_was_set = true; + } + + void SetDefaultValue(const ArchSpec &value) { m_default_value = value; } + +protected: + ArchSpec m_current_value; + ArchSpec m_default_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueArch_h_ diff --git a/include/lldb/Interpreter/OptionValueArgs.h b/include/lldb/Interpreter/OptionValueArgs.h new file mode 100644 index 000000000..433679da1 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueArgs.h @@ -0,0 +1,36 @@ +//===-- OptionValueArgs.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueArgs_h_ +#define liblldb_OptionValueArgs_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValueArray.h" + +namespace lldb_private { + +class OptionValueArgs : public OptionValueArray { +public: + OptionValueArgs() + : OptionValueArray( + OptionValue::ConvertTypeToMask(OptionValue::eTypeString)) {} + + ~OptionValueArgs() override {} + + size_t GetArgs(Args &args); + + Type GetType() const override { return eTypeArgs; } +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueArgs_h_ diff --git a/include/lldb/Interpreter/OptionValueArray.h b/include/lldb/Interpreter/OptionValueArray.h new file mode 100644 index 000000000..bbf4e371a --- /dev/null +++ b/include/lldb/Interpreter/OptionValueArray.h @@ -0,0 +1,137 @@ +//===-- OptionValueArray.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueArray_h_ +#define liblldb_OptionValueArray_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueArray : public OptionValue { +public: + OptionValueArray(uint32_t type_mask = UINT32_MAX, bool raw_value_dump = false) + : m_type_mask(type_mask), m_values(), m_raw_value_dump(raw_value_dump) {} + + ~OptionValueArray() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeArray; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_values.clear(); + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + bool IsAggregateValue() const override { return true; } + + lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx, + llvm::StringRef name, bool will_modify, + Status &error) const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + size_t GetSize() const { return m_values.size(); } + + lldb::OptionValueSP operator[](size_t idx) const { + lldb::OptionValueSP value_sp; + if (idx < m_values.size()) + value_sp = m_values[idx]; + return value_sp; + } + + lldb::OptionValueSP GetValueAtIndex(size_t idx) const { + lldb::OptionValueSP value_sp; + if (idx < m_values.size()) + value_sp = m_values[idx]; + return value_sp; + } + + bool AppendValue(const lldb::OptionValueSP &value_sp) { + // Make sure the value_sp object is allowed to contain + // values of the type passed in... + if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) { + m_values.push_back(value_sp); + return true; + } + return false; + } + + bool InsertValue(size_t idx, const lldb::OptionValueSP &value_sp) { + // Make sure the value_sp object is allowed to contain + // values of the type passed in... + if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) { + if (idx < m_values.size()) + m_values.insert(m_values.begin() + idx, value_sp); + else + m_values.push_back(value_sp); + return true; + } + return false; + } + + bool ReplaceValue(size_t idx, const lldb::OptionValueSP &value_sp) { + // Make sure the value_sp object is allowed to contain + // values of the type passed in... + if (value_sp && (m_type_mask & value_sp->GetTypeAsMask())) { + if (idx < m_values.size()) { + m_values[idx] = value_sp; + return true; + } + } + return false; + } + + bool DeleteValue(size_t idx) { + if (idx < m_values.size()) { + m_values.erase(m_values.begin() + idx); + return true; + } + return false; + } + + size_t GetArgs(Args &args) const; + + Status SetArgs(const Args &args, VarSetOperationType op); + +protected: + typedef std::vector collection; + + uint32_t m_type_mask; + collection m_values; + bool m_raw_value_dump; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueArray_h_ diff --git a/include/lldb/Interpreter/OptionValueBoolean.h b/include/lldb/Interpreter/OptionValueBoolean.h new file mode 100644 index 000000000..1ff84dd33 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueBoolean.h @@ -0,0 +1,100 @@ +//===-- OptionValueBoolean.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueBoolean_h_ +#define liblldb_OptionValueBoolean_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueBoolean : public OptionValue { +public: + OptionValueBoolean(bool value) + : OptionValue(), m_current_value(value), m_default_value(value) {} + OptionValueBoolean(bool current_value, bool default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value) {} + + ~OptionValueBoolean() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeBoolean; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + size_t AutoComplete(CommandInterpreter &interpreter, llvm::StringRef s, + int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + //------------------------------------------------------------------ + /// Convert to bool operator. + /// + /// This allows code to check a OptionValueBoolean in conditions. + /// + /// @code + /// OptionValueBoolean bool_value(...); + /// if (bool_value) + /// { ... + /// @endcode + /// + /// @return + /// /b True this object contains a valid namespace decl, \b + /// false otherwise. + //------------------------------------------------------------------ + explicit operator bool() const { return m_current_value; } + + const bool &operator=(bool b) { + m_current_value = b; + return m_current_value; + } + + bool GetCurrentValue() const { return m_current_value; } + + bool GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(bool value) { m_current_value = value; } + + void SetDefaultValue(bool value) { m_default_value = value; } + + lldb::OptionValueSP DeepCopy() const override; + +protected: + bool m_current_value; + bool m_default_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueBoolean_h_ diff --git a/include/lldb/Interpreter/OptionValueChar.h b/include/lldb/Interpreter/OptionValueChar.h new file mode 100644 index 000000000..0c5f602ef --- /dev/null +++ b/include/lldb/Interpreter/OptionValueChar.h @@ -0,0 +1,80 @@ +//===-- OptionValueBoolean.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueChar_h_ +#define liblldb_OptionValueChar_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueChar : public OptionValue { +public: + OptionValueChar(char value) + : OptionValue(), m_current_value(value), m_default_value(value) {} + + OptionValueChar(char current_value, char default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value) {} + + ~OptionValueChar() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeChar; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + const char &operator=(char c) { + m_current_value = c; + return m_current_value; + } + + char GetCurrentValue() const { return m_current_value; } + + char GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(char value) { m_current_value = value; } + + void SetDefaultValue(char value) { m_default_value = value; } + + lldb::OptionValueSP DeepCopy() const override; + +protected: + char m_current_value; + char m_default_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueChar_h_ diff --git a/include/lldb/Interpreter/OptionValueDictionary.h b/include/lldb/Interpreter/OptionValueDictionary.h new file mode 100644 index 000000000..4e8c86008 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueDictionary.h @@ -0,0 +1,93 @@ +//===-- OptionValueDictionary.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueDictionary_h_ +#define liblldb_OptionValueDictionary_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueDictionary : public OptionValue { +public: + OptionValueDictionary(uint32_t type_mask = UINT32_MAX, + bool raw_value_dump = true) + : OptionValue(), m_type_mask(type_mask), m_values(), + m_raw_value_dump(raw_value_dump) {} + + ~OptionValueDictionary() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeDictionary; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + + bool Clear() override { + m_values.clear(); + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + bool IsAggregateValue() const override { return true; } + + bool IsHomogenous() const { + return ConvertTypeMaskToType(m_type_mask) != eTypeInvalid; + } + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + size_t GetNumValues() const { return m_values.size(); } + + lldb::OptionValueSP GetValueForKey(const ConstString &key) const; + + lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx, + llvm::StringRef name, bool will_modify, + Status &error) const override; + + Status SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op, + llvm::StringRef name, llvm::StringRef value) override; + + bool SetValueForKey(const ConstString &key, + const lldb::OptionValueSP &value_sp, + bool can_replace = true); + + bool DeleteValueForKey(const ConstString &key); + + size_t GetArgs(Args &args) const; + + Status SetArgs(const Args &args, VarSetOperationType op); + +protected: + typedef std::map collection; + uint32_t m_type_mask; + collection m_values; + bool m_raw_value_dump; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueDictionary_h_ diff --git a/include/lldb/Interpreter/OptionValueEnumeration.h b/include/lldb/Interpreter/OptionValueEnumeration.h new file mode 100644 index 000000000..4aa8823e6 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueEnumeration.h @@ -0,0 +1,93 @@ +//===-- OptionValueEnumeration.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueEnumeration_h_ +#define liblldb_OptionValueEnumeration_h_ + +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/lldb-private-types.h" + +namespace lldb_private { + +class OptionValueEnumeration : public OptionValue { +public: + typedef int64_t enum_type; + struct EnumeratorInfo { + enum_type value; + const char *description; + }; + typedef UniqueCStringMap EnumerationMap; + typedef EnumerationMap::Entry EnumerationMapEntry; + + OptionValueEnumeration(const OptionEnumValueElement *enumerators, + enum_type value); + + ~OptionValueEnumeration() override; + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeEnum; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + size_t AutoComplete(CommandInterpreter &interpreter, llvm::StringRef s, + int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + enum_type operator=(enum_type value) { + m_current_value = value; + return m_current_value; + } + + enum_type GetCurrentValue() const { return m_current_value; } + + enum_type GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(enum_type value) { m_current_value = value; } + + void SetDefaultValue(enum_type value) { m_default_value = value; } + +protected: + void SetEnumerations(const OptionEnumValueElement *enumerators); + + enum_type m_current_value; + enum_type m_default_value; + EnumerationMap m_enumerations; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueEnumeration_h_ diff --git a/include/lldb/Interpreter/OptionValueFileSpec.h b/include/lldb/Interpreter/OptionValueFileSpec.h new file mode 100644 index 000000000..b53c03471 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueFileSpec.h @@ -0,0 +1,95 @@ +//===-- OptionValueFileSpec.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueFileSpec_h_ +#define liblldb_OptionValueFileSpec_h_ + +#include "lldb/Interpreter/OptionValue.h" + +#include "lldb/Utility/FileSpec.h" +#include "llvm/Support/Chrono.h" + +namespace lldb_private { + +class OptionValueFileSpec : public OptionValue { +public: + OptionValueFileSpec(bool resolve = true); + + OptionValueFileSpec(const FileSpec &value, bool resolve = true); + + OptionValueFileSpec(const FileSpec ¤t_value, + const FileSpec &default_value, bool resolve = true); + + ~OptionValueFileSpec() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeFileSpec; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + m_data_sp.reset(); + m_data_mod_time = llvm::sys::TimePoint<>(); + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + size_t AutoComplete(CommandInterpreter &interpreter, llvm::StringRef s, + int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + FileSpec &GetCurrentValue() { return m_current_value; } + + const FileSpec &GetCurrentValue() const { return m_current_value; } + + const FileSpec &GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(const FileSpec &value, bool set_value_was_set) { + m_current_value = value; + if (set_value_was_set) + m_value_was_set = true; + m_data_sp.reset(); + } + + void SetDefaultValue(const FileSpec &value) { m_default_value = value; } + + const lldb::DataBufferSP &GetFileContents(bool null_terminate); + + void SetCompletionMask(uint32_t mask) { m_completion_mask = mask; } + +protected: + FileSpec m_current_value; + FileSpec m_default_value; + lldb::DataBufferSP m_data_sp; + llvm::sys::TimePoint<> m_data_mod_time; + uint32_t m_completion_mask; + bool m_resolve; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueFileSpec_h_ diff --git a/include/lldb/Interpreter/OptionValueFileSpecList.h b/include/lldb/Interpreter/OptionValueFileSpecList.h new file mode 100644 index 000000000..9529fbcf3 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueFileSpecList.h @@ -0,0 +1,73 @@ +//===-- OptionValueFileSpecList.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueFileSpecList_h_ +#define liblldb_OptionValueFileSpecList_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/FileSpecList.h" +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueFileSpecList : public OptionValue { +public: + OptionValueFileSpecList() : OptionValue(), m_current_value() {} + + OptionValueFileSpecList(const FileSpecList ¤t_value) + : OptionValue(), m_current_value(current_value) {} + + ~OptionValueFileSpecList() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeFileSpecList; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value.Clear(); + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + bool IsAggregateValue() const override { return true; } + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + FileSpecList &GetCurrentValue() { return m_current_value; } + + const FileSpecList &GetCurrentValue() const { return m_current_value; } + + void SetCurrentValue(const FileSpecList &value) { m_current_value = value; } + +protected: + FileSpecList m_current_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueFileSpecList_h_ diff --git a/include/lldb/Interpreter/OptionValueFormat.h b/include/lldb/Interpreter/OptionValueFormat.h new file mode 100644 index 000000000..ce7997024 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueFormat.h @@ -0,0 +1,75 @@ +//===-- OptionValueFormat.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueFormat_h_ +#define liblldb_OptionValueFormat_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueFormat : public OptionValue { +public: + OptionValueFormat(lldb::Format value) + : OptionValue(), m_current_value(value), m_default_value(value) {} + + OptionValueFormat(lldb::Format current_value, lldb::Format default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value) {} + + ~OptionValueFormat() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeFormat; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + lldb::Format GetCurrentValue() const { return m_current_value; } + + lldb::Format GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(lldb::Format value) { m_current_value = value; } + + void SetDefaultValue(lldb::Format value) { m_default_value = value; } + +protected: + lldb::Format m_current_value; + lldb::Format m_default_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueFormat_h_ diff --git a/include/lldb/Interpreter/OptionValueFormatEntity.h b/include/lldb/Interpreter/OptionValueFormatEntity.h new file mode 100644 index 000000000..e5a65b7e7 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueFormatEntity.h @@ -0,0 +1,77 @@ +//===-- OptionValueFormatEntity.h --------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueFormatEntity_h_ +#define liblldb_OptionValueFormatEntity_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/FormatEntity.h" +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueFormatEntity : public OptionValue { +public: + OptionValueFormatEntity(const char *default_format); + + ~OptionValueFormatEntity() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeFormatEntity; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override; + + lldb::OptionValueSP DeepCopy() const override; + + size_t AutoComplete(CommandInterpreter &interpreter, llvm::StringRef s, + int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + FormatEntity::Entry &GetCurrentValue() { return m_current_entry; } + + const FormatEntity::Entry &GetCurrentValue() const { return m_current_entry; } + + void SetCurrentValue(const FormatEntity::Entry &value) { + m_current_entry = value; + } + + FormatEntity::Entry &GetDefaultValue() { return m_default_entry; } + + const FormatEntity::Entry &GetDefaultValue() const { return m_default_entry; } + +protected: + std::string m_current_format; + std::string m_default_format; + FormatEntity::Entry m_current_entry; + FormatEntity::Entry m_default_entry; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueFormatEntity_h_ diff --git a/include/lldb/Interpreter/OptionValueLanguage.h b/include/lldb/Interpreter/OptionValueLanguage.h new file mode 100644 index 000000000..8f81c5df0 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueLanguage.h @@ -0,0 +1,78 @@ +//===-- OptionValueLanguage.h -------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueLanguage_h_ +#define liblldb_OptionValueLanguage_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/lldb-enumerations.h" + +namespace lldb_private { + +class OptionValueLanguage : public OptionValue { +public: + OptionValueLanguage(lldb::LanguageType value) + : OptionValue(), m_current_value(value), m_default_value(value) {} + + OptionValueLanguage(lldb::LanguageType current_value, + lldb::LanguageType default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value) {} + + ~OptionValueLanguage() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeLanguage; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + lldb::LanguageType GetCurrentValue() const { return m_current_value; } + + lldb::LanguageType GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(lldb::LanguageType value) { m_current_value = value; } + + void SetDefaultValue(lldb::LanguageType value) { m_default_value = value; } + +protected: + lldb::LanguageType m_current_value; + lldb::LanguageType m_default_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueLanguage_h_ diff --git a/include/lldb/Interpreter/OptionValuePathMappings.h b/include/lldb/Interpreter/OptionValuePathMappings.h new file mode 100644 index 000000000..0e2e98d74 --- /dev/null +++ b/include/lldb/Interpreter/OptionValuePathMappings.h @@ -0,0 +1,70 @@ +//===-- OptionValuePathMappings.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValuePathMappings_h_ +#define liblldb_OptionValuePathMappings_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Target/PathMappingList.h" + +namespace lldb_private { + +class OptionValuePathMappings : public OptionValue { +public: + OptionValuePathMappings(bool notify_changes) + : OptionValue(), m_path_mappings(), m_notify_changes(notify_changes) {} + + ~OptionValuePathMappings() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypePathMap; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_path_mappings.Clear(m_notify_changes); + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + bool IsAggregateValue() const override { return true; } + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + PathMappingList &GetCurrentValue() { return m_path_mappings; } + + const PathMappingList &GetCurrentValue() const { return m_path_mappings; } + +protected: + PathMappingList m_path_mappings; + bool m_notify_changes; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValuePathMappings_h_ diff --git a/include/lldb/Interpreter/OptionValueProperties.h b/include/lldb/Interpreter/OptionValueProperties.h new file mode 100644 index 000000000..16d31aa4e --- /dev/null +++ b/include/lldb/Interpreter/OptionValueProperties.h @@ -0,0 +1,235 @@ +//===-- OptionValueProperties.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueProperties_h_ +#define liblldb_OptionValueProperties_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/FormatEntity.h" +#include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Interpreter/Property.h" +#include "lldb/Utility/ConstString.h" + +namespace lldb_private { + +class OptionValueProperties + : public OptionValue, + public std::enable_shared_from_this { +public: + OptionValueProperties() + : OptionValue(), m_name(), m_properties(), m_name_to_index() {} + + OptionValueProperties(const ConstString &name); + + OptionValueProperties(const OptionValueProperties &global_properties); + + ~OptionValueProperties() override = default; + + Type GetType() const override { return eTypeProperties; } + + bool Clear() override; + + lldb::OptionValueSP DeepCopy() const override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + ConstString GetName() const override { return m_name; } + + virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx, + Stream &strm, llvm::StringRef property_path, + uint32_t dump_mask); + + virtual void DumpAllDescriptions(CommandInterpreter &interpreter, + Stream &strm) const; + + void Apropos(llvm::StringRef keyword, + std::vector &matching_properties) const; + + void Initialize(const PropertyDefinition *setting_definitions); + + // bool + // GetQualifiedName (Stream &strm); + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + virtual size_t GetNumProperties() const; + + //--------------------------------------------------------------------- + // Get the index of a property given its exact name in this property + // collection, "name" can't be a path to a property path that refers + // to a property within a property + //--------------------------------------------------------------------- + virtual uint32_t GetPropertyIndex(const ConstString &name) const; + + //--------------------------------------------------------------------- + // Get a property by exact name exists in this property collection, name + // can not be a path to a property path that refers to a property within + // a property + //--------------------------------------------------------------------- + virtual const Property *GetProperty(const ExecutionContext *exe_ctx, + bool will_modify, + const ConstString &name) const; + + virtual const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, + bool will_modify, + uint32_t idx) const; + + //--------------------------------------------------------------------- + // Property can be be a property path like + // "target.process.extra-startup-command" + //--------------------------------------------------------------------- + virtual const Property *GetPropertyAtPath(const ExecutionContext *exe_ctx, + bool will_modify, + llvm::StringRef property_path) const; + + virtual lldb::OptionValueSP + GetPropertyValueAtIndex(const ExecutionContext *exe_ctx, bool will_modify, + uint32_t idx) const; + + virtual lldb::OptionValueSP GetValueForKey(const ExecutionContext *exe_ctx, + const ConstString &key, + bool value_will_be_modified) const; + + lldb::OptionValueSP GetSubValue(const ExecutionContext *exe_ctx, + llvm::StringRef name, + bool value_will_be_modified, + Status &error) const override; + + Status SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op, + llvm::StringRef path, llvm::StringRef value) override; + + virtual bool PredicateMatches(const ExecutionContext *exe_ctx, + llvm::StringRef predicate) const { + return false; + } + + OptionValueArch * + GetPropertyAtIndexAsOptionValueArch(const ExecutionContext *exe_ctx, + uint32_t idx) const; + + OptionValueLanguage * + GetPropertyAtIndexAsOptionValueLanguage(const ExecutionContext *exe_ctx, + uint32_t idx) const; + + bool GetPropertyAtIndexAsArgs(const ExecutionContext *exe_ctx, uint32_t idx, + Args &args) const; + + bool SetPropertyAtIndexFromArgs(const ExecutionContext *exe_ctx, uint32_t idx, + const Args &args); + + bool GetPropertyAtIndexAsBoolean(const ExecutionContext *exe_ctx, + uint32_t idx, bool fail_value) const; + + bool SetPropertyAtIndexAsBoolean(const ExecutionContext *exe_ctx, + uint32_t idx, bool new_value); + + OptionValueDictionary * + GetPropertyAtIndexAsOptionValueDictionary(const ExecutionContext *exe_ctx, + uint32_t idx) const; + + int64_t GetPropertyAtIndexAsEnumeration(const ExecutionContext *exe_ctx, + uint32_t idx, + int64_t fail_value) const; + + bool SetPropertyAtIndexAsEnumeration(const ExecutionContext *exe_ctx, + uint32_t idx, int64_t new_value); + + const FormatEntity::Entry * + GetPropertyAtIndexAsFormatEntity(const ExecutionContext *exe_ctx, + uint32_t idx); + + const RegularExpression * + GetPropertyAtIndexAsOptionValueRegex(const ExecutionContext *exe_ctx, + uint32_t idx) const; + + OptionValueSInt64 * + GetPropertyAtIndexAsOptionValueSInt64(const ExecutionContext *exe_ctx, + uint32_t idx) const; + + int64_t GetPropertyAtIndexAsSInt64(const ExecutionContext *exe_ctx, + uint32_t idx, int64_t fail_value) const; + + bool SetPropertyAtIndexAsSInt64(const ExecutionContext *exe_ctx, uint32_t idx, + int64_t new_value); + + uint64_t GetPropertyAtIndexAsUInt64(const ExecutionContext *exe_ctx, + uint32_t idx, uint64_t fail_value) const; + + bool SetPropertyAtIndexAsUInt64(const ExecutionContext *exe_ctx, uint32_t idx, + uint64_t new_value); + + llvm::StringRef GetPropertyAtIndexAsString(const ExecutionContext *exe_ctx, + uint32_t idx, + llvm::StringRef fail_value) const; + + bool SetPropertyAtIndexAsString(const ExecutionContext *exe_ctx, uint32_t idx, + llvm::StringRef new_value); + + OptionValueString * + GetPropertyAtIndexAsOptionValueString(const ExecutionContext *exe_ctx, + bool will_modify, uint32_t idx) const; + + OptionValueFileSpec * + GetPropertyAtIndexAsOptionValueFileSpec(const ExecutionContext *exe_ctx, + bool will_modify, uint32_t idx) const; + + FileSpec GetPropertyAtIndexAsFileSpec(const ExecutionContext *exe_ctx, + uint32_t idx) const; + + bool SetPropertyAtIndexAsFileSpec(const ExecutionContext *exe_ctx, + uint32_t idx, const FileSpec &file_spec); + + OptionValuePathMappings *GetPropertyAtIndexAsOptionValuePathMappings( + const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const; + + OptionValueFileSpecList *GetPropertyAtIndexAsOptionValueFileSpecList( + const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const; + + void AppendProperty(const ConstString &name, const ConstString &desc, + bool is_global, const lldb::OptionValueSP &value_sp); + + lldb::OptionValuePropertiesSP GetSubProperty(const ExecutionContext *exe_ctx, + const ConstString &name); + + void SetValueChangedCallback(uint32_t property_idx, + OptionValueChangedCallback callback, + void *baton); + +protected: + Property *ProtectedGetPropertyAtIndex(uint32_t idx) { + return ((idx < m_properties.size()) ? &m_properties[idx] : nullptr); + } + + const Property *ProtectedGetPropertyAtIndex(uint32_t idx) const { + return ((idx < m_properties.size()) ? &m_properties[idx] : nullptr); + } + + typedef UniqueCStringMap NameToIndex; + + ConstString m_name; + std::vector m_properties; + NameToIndex m_name_to_index; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueProperties_h_ diff --git a/include/lldb/Interpreter/OptionValueRegex.h b/include/lldb/Interpreter/OptionValueRegex.h new file mode 100644 index 000000000..afe9318ae --- /dev/null +++ b/include/lldb/Interpreter/OptionValueRegex.h @@ -0,0 +1,75 @@ +//===-- OptionValueRegex.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueRegex_h_ +#define liblldb_OptionValueRegex_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Utility/RegularExpression.h" + +namespace lldb_private { + +class OptionValueRegex : public OptionValue { +public: + OptionValueRegex(const char *value = nullptr) + : OptionValue(), m_regex(llvm::StringRef::withNullAsEmpty(value)) {} + + ~OptionValueRegex() override = default; + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeRegex; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_regex.Clear(); + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + const RegularExpression *GetCurrentValue() const { + return (m_regex.IsValid() ? &m_regex : nullptr); + } + + void SetCurrentValue(const char *value) { + if (value && value[0]) + m_regex.Compile(llvm::StringRef(value)); + else + m_regex.Clear(); + } + + bool IsValid() const { return m_regex.IsValid(); } + +protected: + RegularExpression m_regex; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueRegex_h_ diff --git a/include/lldb/Interpreter/OptionValueSInt64.h b/include/lldb/Interpreter/OptionValueSInt64.h new file mode 100644 index 000000000..a6893d23e --- /dev/null +++ b/include/lldb/Interpreter/OptionValueSInt64.h @@ -0,0 +1,114 @@ +//===-- OptionValueSInt64.h --------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueSInt64_h_ +#define liblldb_OptionValueSInt64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueSInt64 : public OptionValue { +public: + OptionValueSInt64() + : OptionValue(), m_current_value(0), m_default_value(0), + m_min_value(INT64_MIN), m_max_value(INT64_MAX) {} + + OptionValueSInt64(int64_t value) + : OptionValue(), m_current_value(value), m_default_value(value), + m_min_value(INT64_MIN), m_max_value(INT64_MAX) {} + + OptionValueSInt64(int64_t current_value, int64_t default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value), m_min_value(INT64_MIN), + m_max_value(INT64_MAX) {} + + OptionValueSInt64(const OptionValueSInt64 &rhs) + : OptionValue(rhs), m_current_value(rhs.m_current_value), + m_default_value(rhs.m_default_value), m_min_value(rhs.m_min_value), + m_max_value(rhs.m_max_value) {} + + ~OptionValueSInt64() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeSInt64; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + const int64_t &operator=(int64_t value) { + m_current_value = value; + return m_current_value; + } + + int64_t GetCurrentValue() const { return m_current_value; } + + int64_t GetDefaultValue() const { return m_default_value; } + + bool SetCurrentValue(int64_t value) { + if (value >= m_min_value && value <= m_max_value) { + m_current_value = value; + return true; + } + return false; + } + + bool SetDefaultValue(int64_t value) { + if (value >= m_min_value && value <= m_max_value) { + m_default_value = value; + return true; + } + return false; + } + + void SetMinimumValue(int64_t v) { m_min_value = v; } + + int64_t GetMinimumValue() const { return m_min_value; } + + void SetMaximumValue(int64_t v) { m_max_value = v; } + + int64_t GetMaximumValue() const { return m_max_value; } + +protected: + int64_t m_current_value; + int64_t m_default_value; + int64_t m_min_value; + int64_t m_max_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueSInt64_h_ diff --git a/include/lldb/Interpreter/OptionValueString.h b/include/lldb/Interpreter/OptionValueString.h new file mode 100644 index 000000000..4a9f22276 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueString.h @@ -0,0 +1,148 @@ +//===-- OptionValueString.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueString_h_ +#define liblldb_OptionValueString_h_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/Flags.h" + +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueString : public OptionValue { +public: + typedef Status (*ValidatorCallback)(const char *string, void *baton); + + enum Options { eOptionEncodeCharacterEscapeSequences = (1u << 0) }; + + OptionValueString() + : OptionValue(), m_current_value(), m_default_value(), m_options(), + m_validator(), m_validator_baton() {} + + OptionValueString(ValidatorCallback validator, void *baton = nullptr) + : OptionValue(), m_current_value(), m_default_value(), m_options(), + m_validator(validator), m_validator_baton(baton) {} + + OptionValueString(const char *value) + : OptionValue(), m_current_value(), m_default_value(), m_options(), + m_validator(), m_validator_baton() { + if (value && value[0]) { + m_current_value.assign(value); + m_default_value.assign(value); + } + } + + OptionValueString(const char *current_value, const char *default_value) + : OptionValue(), m_current_value(), m_default_value(), m_options(), + m_validator(), m_validator_baton() { + if (current_value && current_value[0]) + m_current_value.assign(current_value); + if (default_value && default_value[0]) + m_default_value.assign(default_value); + } + + OptionValueString(const char *value, ValidatorCallback validator, + void *baton = nullptr) + : OptionValue(), m_current_value(), m_default_value(), m_options(), + m_validator(validator), m_validator_baton(baton) { + if (value && value[0]) { + m_current_value.assign(value); + m_default_value.assign(value); + } + } + + OptionValueString(const char *current_value, const char *default_value, + ValidatorCallback validator, void *baton = nullptr) + : OptionValue(), m_current_value(), m_default_value(), m_options(), + m_validator(validator), m_validator_baton(baton) { + if (current_value && current_value[0]) + m_current_value.assign(current_value); + if (default_value && default_value[0]) + m_default_value.assign(default_value); + } + + ~OptionValueString() override = default; + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeString; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + Flags &GetOptions() { return m_options; } + + const Flags &GetOptions() const { return m_options; } + + const char *operator=(const char *value) { + SetCurrentValue(llvm::StringRef::withNullAsEmpty(value)); + return m_current_value.c_str(); + } + + const char *GetCurrentValue() const { return m_current_value.c_str(); } + llvm::StringRef GetCurrentValueAsRef() const { return m_current_value; } + + const char *GetDefaultValue() const { return m_default_value.c_str(); } + llvm::StringRef GetDefaultValueAsRef() const { return m_default_value; } + + Status SetCurrentValue(const char *) = delete; + Status SetCurrentValue(llvm::StringRef value); + + Status AppendToCurrentValue(const char *value); + + void SetDefaultValue(const char *value) { + if (value && value[0]) + m_default_value.assign(value); + else + m_default_value.clear(); + } + + bool IsCurrentValueEmpty() const { return m_current_value.empty(); } + + bool IsDefaultValueEmpty() const { return m_default_value.empty(); } + +protected: + std::string m_current_value; + std::string m_default_value; + Flags m_options; + ValidatorCallback m_validator; + void *m_validator_baton; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueString_h_ diff --git a/include/lldb/Interpreter/OptionValueUInt64.h b/include/lldb/Interpreter/OptionValueUInt64.h new file mode 100644 index 000000000..be13ff073 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueUInt64.h @@ -0,0 +1,93 @@ +//===-- OptionValueUInt64.h --------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueUInt64_h_ +#define liblldb_OptionValueUInt64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueUInt64 : public OptionValue { +public: + OptionValueUInt64() : OptionValue(), m_current_value(0), m_default_value(0) {} + + OptionValueUInt64(uint64_t value) + : OptionValue(), m_current_value(value), m_default_value(value) {} + + OptionValueUInt64(uint64_t current_value, uint64_t default_value) + : OptionValue(), m_current_value(current_value), + m_default_value(default_value) {} + + ~OptionValueUInt64() override {} + + //--------------------------------------------------------------------- + // Decode a uint64_t from "value_cstr" return a OptionValueUInt64 object + // inside of a lldb::OptionValueSP object if all goes well. If the + // string isn't a uint64_t value or any other error occurs, return an + // empty lldb::OptionValueSP and fill error in with the correct stuff. + //--------------------------------------------------------------------- + static lldb::OptionValueSP Create(const char *, Status &) = delete; + static lldb::OptionValueSP Create(llvm::StringRef value_str, Status &error); + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeUInt64; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_current_value = m_default_value; + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + const uint64_t &operator=(uint64_t value) { + m_current_value = value; + return m_current_value; + } + + operator uint64_t() const { return m_current_value; } + + uint64_t GetCurrentValue() const { return m_current_value; } + + uint64_t GetDefaultValue() const { return m_default_value; } + + void SetCurrentValue(uint64_t value) { m_current_value = value; } + + void SetDefaultValue(uint64_t value) { m_default_value = value; } + +protected: + uint64_t m_current_value; + uint64_t m_default_value; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueUInt64_h_ diff --git a/include/lldb/Interpreter/OptionValueUUID.h b/include/lldb/Interpreter/OptionValueUUID.h new file mode 100644 index 000000000..6e0aeebb0 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueUUID.h @@ -0,0 +1,74 @@ +//===-- OptionValueUUID.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValueUUID_h_ +#define liblldb_OptionValueUUID_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Utility/UUID.h" +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueUUID : public OptionValue { +public: + OptionValueUUID() : OptionValue(), m_uuid() {} + + OptionValueUUID(const UUID &uuid) : OptionValue(), m_uuid(uuid) {} + + ~OptionValueUUID() override {} + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type GetType() const override { return eTypeUUID; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + Status + SetValueFromString(const char *, + VarSetOperationType = eVarSetOperationAssign) = delete; + + bool Clear() override { + m_uuid.Clear(); + m_value_was_set = false; + return true; + } + + lldb::OptionValueSP DeepCopy() const override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + UUID &GetCurrentValue() { return m_uuid; } + + const UUID &GetCurrentValue() const { return m_uuid; } + + void SetCurrentValue(const UUID &value) { m_uuid = value; } + + size_t AutoComplete(CommandInterpreter &interpreter, llvm::StringRef s, + int match_start_point, int max_return_elements, + bool &word_complete, StringList &matches) override; + +protected: + UUID m_uuid; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueUUID_h_ diff --git a/include/lldb/Interpreter/OptionValues.h b/include/lldb/Interpreter/OptionValues.h new file mode 100644 index 000000000..e177d743f --- /dev/null +++ b/include/lldb/Interpreter/OptionValues.h @@ -0,0 +1,34 @@ +//===-- OptionValues.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_OptionValues_h_ +#define liblldb_OptionValues_h_ + +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Interpreter/OptionValueArch.h" +#include "lldb/Interpreter/OptionValueArgs.h" +#include "lldb/Interpreter/OptionValueArray.h" +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueChar.h" +#include "lldb/Interpreter/OptionValueDictionary.h" +#include "lldb/Interpreter/OptionValueEnumeration.h" +#include "lldb/Interpreter/OptionValueFileSpec.h" +#include "lldb/Interpreter/OptionValueFileSpecList.h" +#include "lldb/Interpreter/OptionValueFormat.h" +#include "lldb/Interpreter/OptionValueFormatEntity.h" +#include "lldb/Interpreter/OptionValueLanguage.h" +#include "lldb/Interpreter/OptionValuePathMappings.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Interpreter/OptionValueRegex.h" +#include "lldb/Interpreter/OptionValueSInt64.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/OptionValueUInt64.h" +#include "lldb/Interpreter/OptionValueUUID.h" + +#endif // liblldb_OptionValues_h_ diff --git a/include/lldb/Interpreter/Options.h b/include/lldb/Interpreter/Options.h new file mode 100644 index 000000000..871210055 --- /dev/null +++ b/include/lldb/Interpreter/Options.h @@ -0,0 +1,432 @@ +//===-- 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 +// C++ Includes +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/Args.h" +#include "lldb/lldb-defines.h" +#include "lldb/lldb-private.h" + +#include "llvm/ADT/ArrayRef.h" + +namespace lldb_private { + +static inline bool isprint8(int ch) { + if (ch & 0xffffff00u) + return false; + return isprint(ch); +} + +//---------------------------------------------------------------------- +/// @class Options Options.h "lldb/Interpreter/Options.h" +/// @brief A command line option parsing protocol class. +/// +/// Options is designed to be subclassed to contain all needed +/// options for a given command. The options can be parsed by calling: +/// \code +/// Status Args::ParseOptions (Options &); +/// \endcode +/// +/// The options are specified using the format defined for the libc +/// options parsing function getopt_long_only: +/// \code +/// #include +/// int getopt_long_only(int argc, char * const *argv, const char +/// *optstring, const struct option *longopts, int *longindex); +/// \endcode +/// +/// Example code: +/// \code +/// #include +/// #include +/// +/// class CommandOptions : public Options +/// { +/// public: +/// virtual struct option * +/// GetLongOptions() { +/// return g_options; +/// } +/// +/// virtual Status +/// SetOptionValue (uint32_t option_idx, int option_val, const char +/// *option_arg) +/// { +/// Status 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, nullptr, 0); break; +/// default: +/// error.SetErrorStringWithFormat("unrecognized short option +/// %c", option_val); +/// break; +/// } +/// +/// return error; +/// } +/// +/// CommandOptions (CommandInterpreter &interpreter) : debug (true), +/// verbose (false), log_file (), log_flags (0) +/// {} +/// +/// bool debug; +/// bool verbose; +/// std::string log_file; +/// uint32_t log_flags; +/// +/// static struct option g_options[]; +/// +/// }; +/// +/// struct option CommandOptions::g_options[] = +/// { +/// { "debug", no_argument, nullptr, 'g' }, +/// { "log-file", required_argument, nullptr, 'l' }, +/// { "log-flags", required_argument, nullptr, 'f' }, +/// { "verbose", no_argument, nullptr, 'v' }, +/// { nullptr, 0, nullptr, 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_only + //------------------------------------------------------------------ + Option *GetLongOptions(); + + // This gets passed the short option as an integer... + void OptionSeen(int short_option); + + bool VerifyOptions(CommandReturnObject &result); + + // Verify that the options given are in the options table and can + // be used together, but there may be some required options that are + // missing (used to verify options that get folded into command aliases). + bool VerifyPartialOptions(CommandReturnObject &result); + + void OutputFormattedUsageText(Stream &strm, + const OptionDefinition &option_def, + uint32_t output_max_columns); + + void GenerateOptionUsage(Stream &strm, CommandObject *cmd, + uint32_t screen_width); + + bool SupportsLongOption(const char *long_option); + + // The following two pure virtual functions must be defined by every + // class that inherits from this class. + + virtual llvm::ArrayRef GetDefinitions() { + return llvm::ArrayRef(); + } + + // Call this prior to parsing any options. This call will call the + // subclass OptionParsingStarting() and will avoid the need for all + // OptionParsingStarting() function instances from having to call the + // Option::OptionParsingStarting() like they did before. This was error + // prone and subclasses shouldn't have to do it. + void NotifyOptionParsingStarting(ExecutionContext *execution_context); + + Status NotifyOptionParsingFinished(ExecutionContext *execution_context); + + //------------------------------------------------------------------ + /// 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 + /// nullptr if there is no argument for the current option. + /// + /// @param[in] execution_context + /// The execution context to use for evaluating the option. + /// May be nullptr if the option is to be evaluated outside any + /// particular context. + /// + /// @see Args::ParseOptions (Options&) + /// @see man getopt_long_only + //------------------------------------------------------------------ + virtual Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) = 0; + + //------------------------------------------------------------------ + /// Handles the generic bits of figuring out whether we are in an + /// option, and if so completing it. + /// + /// @param[in] input + /// The command line parsed into words + /// + /// @param[in] cursor_index + /// The index in \ainput of the word in which the cursor lies. + /// + /// @param[in] char_pos + /// The character position of the cursor in its argument word. + /// + /// @param[in] match_start_point + /// @param[in] match_return_elements + /// See CommandObject::HandleCompletions for a description of + /// how these work. + /// + /// @param[in] interpreter + /// The interpreter that's doing the completing. + /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will be + /// inserted after the completion.) \b false otherwise. + /// + /// @param[out] matches + /// The array of matches returned. + /// + /// FIXME: This is the wrong return value, since we also need to + /// make a distinction between total number of matches, and the + /// window the user wants returned. + /// + /// @return + /// \btrue if we were in an option, \bfalse otherwise. + //------------------------------------------------------------------ + bool HandleOptionCompletion(Args &input, OptionElementVector &option_map, + int cursor_index, int char_pos, + int match_start_point, int max_return_elements, + CommandInterpreter &interpreter, + bool &word_complete, + lldb_private::StringList &matches); + + //------------------------------------------------------------------ + /// Handles the generic bits of figuring out whether we are in an + /// option, and if so completing it. + /// + /// @param[in] interpreter + /// The command interpreter doing the completion. + /// + /// @param[in] input + /// The command line parsed into words + /// + /// @param[in] cursor_index + /// The index in \ainput of the word in which the cursor lies. + /// + /// @param[in] char_pos + /// The character position of the cursor in its argument word. + /// + /// @param[in] opt_element_vector + /// The results of the options parse of \a input. + /// + /// @param[in] opt_element_index + /// The position in \a opt_element_vector of the word in \a + /// input containing the cursor. + /// + /// @param[in] match_start_point + /// @param[in] match_return_elements + /// See CommandObject::HandleCompletions for a description of + /// how these work. + /// + /// @param[in] interpreter + /// The command interpreter in which we're doing completion. + /// + /// @param[out] word_complete + /// \btrue if this is a complete option value (a space will + /// be inserted after the completion.) \bfalse otherwise. + /// + /// @param[out] matches + /// The array of matches returned. + /// + /// FIXME: This is the wrong return value, since we also need to + /// make a distinction between total number of matches, and the + /// window the user wants returned. + /// + /// @return + /// \btrue if we were in an option, \bfalse otherwise. + //------------------------------------------------------------------ + virtual bool + HandleOptionArgumentCompletion(Args &input, int cursor_index, int char_pos, + OptionElementVector &opt_element_vector, + int opt_element_index, int match_start_point, + int max_return_elements, + CommandInterpreter &interpreter, + bool &word_complete, StringList &matches); + +protected: + // This is a set of options expressed as indexes into the options table for + // this Option. + typedef std::set OptionSet; + typedef std::vector OptionSetVector; + + std::vector