[Lldb-commits] [lldb] r339911 - Add a new tool named "lldb-vscode" that implements the Visual Studio Code Debug Adaptor Protocol

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Fri Aug 17 10:32:18 PDT 2018


I just committed:

$ svn commit
Sending        packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py
Transmitting file data .done
Committing transaction...
Committed revision 340050.

This now uses self.assertEqual so we can see if we are getting no breakpoints. It will give a bit more signal on what is going on.

> On Aug 17, 2018, at 10:17 AM, Adrian Prantl <aprantl at apple.com> wrote:
> 
> 
> 
>> On Aug 17, 2018, at 10:15 AM, Greg Clayton <clayborg at gmail.com <mailto:clayborg at gmail.com>> wrote:
>> 
>> Is this flaky or does it fail all the time? If it fails all the time let me know and I will change the test to give us better error message when it fails so we can figure out what is going on.
> 
> This fails all the time, but our sample size isn't particularly large because upstream LLVM was broken for the last 12 hours.
> 
> -- adrian
> 
>> 
>> In order to test by name i copy the a.out to a temp file and then launch it:
>> 
>>         program = tempfile.mktemp()
>>         shutil.copyfile(orig_program, program)
>>         shutil.copymode(orig_program, program)
>>         self.process = subprocess.Popen([program],
>>                                         stdin=subprocess.PIPE,
>>                                         stdout=subprocess.PIPE,
>>                                         stderr=subprocess.PIPE)
>> 
>> Otherwise this is the exact same test as test_by_name that passed. Not sure what could be going on here.
>> 
>> Greg
>> 
>>> On Aug 17, 2018, at 9:35 AM, Adrian Prantl via lldb-commits <lldb-commits at lists.llvm.org <mailto:lldb-commits at lists.llvm.org>> wrote:
>>> 
>>> Greg, could you please take a look at the failure in lldb-vscode/attach/TestVSCode_attach.py ?
>>> 
>>> http://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/9014/testReport/junit/lldb-Suite/tools_lldb-vscode_attach/TestVSCode_attach_py/ <http://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/9014/testReport/junit/lldb-Suite/tools_lldb-vscode_attach/TestVSCode_attach_py/>
>>> 
>>> ======================================================================
>>> FAIL: test_by_name_waitFor (TestVSCode_attach.TestVSCode_attach)
>>> ----------------------------------------------------------------------
>>> Traceback (most recent call last):
>>>   File "/Users/buildslave/jenkins/workspace/lldb-cmake/src/llvm/tools/lldb/packages/Python/lldbsuite/test/decorators.py", line 341, in wrapper
>>>     return func(self, *args, **kwargs)
>>>   File "/Users/buildslave/jenkins/workspace/lldb-cmake/src/llvm/tools/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py", line 102, in test_by_name_waitFor
>>>     self.set_and_hit_breakpoint(continueToExit=True)
>>>   File "/Users/buildslave/jenkins/workspace/lldb-cmake/src/llvm/tools/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py", line 41, in set_and_hit_breakpoint
>>>     "expect correct number of breakpoints")
>>> AssertionError: False is not True : expect correct number of breakpoints
>>> Config=x86_64-/Users/buildslave/jenkins/workspace/lldb-cmake/build/bin/clang-8
>>> 
>>> 
>>> thanks!
>>> adrian
>>> 
>>>> On Aug 16, 2018, at 10:59 AM, Greg Clayton via lldb-commits <lldb-commits at lists.llvm.org <mailto:lldb-commits at lists.llvm.org>> wrote:
>>>> 
>>>> Author: gclayton
>>>> Date: Thu Aug 16 10:59:38 2018
>>>> New Revision: 339911
>>>> 
>>>> URL: http://llvm.org/viewvc/llvm-project?rev=339911&view=rev <http://llvm.org/viewvc/llvm-project?rev=339911&view=rev>
>>>> Log:
>>>> Add a new tool named "lldb-vscode" that implements the Visual Studio Code Debug Adaptor Protocol
>>>> 
>>>> This patch adds a new lldb-vscode tool that speaks the Microsoft Visual Studio Code debug adaptor protocol. It has full unit tests that test all packets.
>>>> 
>>>> This tool can be easily packaged up into a native extension and used with Visual Studio Code, and it can also be used by Nuclide
>>>> 
>>>> Differential Revision: https://reviews.llvm.org/D50365 <https://reviews.llvm.org/D50365>
>>>> 
>>>> 
>>>> Added:
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/.categories
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/Makefile
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/main.c
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/Makefile
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setExceptionBreakpoints.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setFunctionBreakpoints.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/main.cpp
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/Makefile
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/TestVSCode_launch.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/main.c
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/Makefile
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/TestVSCode_stackTrace.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/main.c
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/Makefile
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/TestVSCode_step.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/main.cpp
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/Makefile
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/main.cpp
>>>>    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
>>>>    lldb/trunk/tools/lldb-vscode/
>>>>    lldb/trunk/tools/lldb-vscode/BreakpointBase.cpp
>>>>    lldb/trunk/tools/lldb-vscode/BreakpointBase.h
>>>>    lldb/trunk/tools/lldb-vscode/CMakeLists.txt
>>>>    lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.cpp
>>>>    lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.h
>>>>    lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.cpp
>>>>    lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.h
>>>>    lldb/trunk/tools/lldb-vscode/JSONUtils.cpp
>>>>    lldb/trunk/tools/lldb-vscode/JSONUtils.h
>>>>    lldb/trunk/tools/lldb-vscode/LLDBUtils.cpp
>>>>    lldb/trunk/tools/lldb-vscode/LLDBUtils.h
>>>>    lldb/trunk/tools/lldb-vscode/README.md
>>>>    lldb/trunk/tools/lldb-vscode/SourceBreakpoint.cpp
>>>>    lldb/trunk/tools/lldb-vscode/SourceBreakpoint.h
>>>>    lldb/trunk/tools/lldb-vscode/SourceReference.h
>>>>    lldb/trunk/tools/lldb-vscode/VSCode.cpp
>>>>    lldb/trunk/tools/lldb-vscode/VSCode.h
>>>>    lldb/trunk/tools/lldb-vscode/VSCodeForward.h
>>>>    lldb/trunk/tools/lldb-vscode/lldb-vscode-Info.plist
>>>>    lldb/trunk/tools/lldb-vscode/lldb-vscode.cpp
>>>>    lldb/trunk/tools/lldb-vscode/package.json
>>>> Modified:
>>>>    lldb/trunk/lldb.xcodeproj/project.pbxproj
>>>>    lldb/trunk/packages/Python/lldbsuite/test/dotest.py
>>>>    lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py
>>>>    lldb/trunk/tools/CMakeLists.txt
>>>> 
>>>> Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=339911&r1=339910&r2=339911&view=diff <http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=339911&r1=339910&r2=339911&view=diff>
>>>> ==============================================================================
>>>> --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
>>>> +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Thu Aug 16 10:59:38 2018
>>>> @@ -119,6 +119,7 @@
>>>> 		268900D013353E6F00698AC0 /* Block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1310F1B8EC00F91463 /* Block.cpp */; };
>>>> 		49DEF1251CD7C6DF006A7C7D /* BlockPointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DEF11F1CD7BD90006A7C7D /* BlockPointer.cpp */; };
>>>> 		2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0A10F1B83100F91463 /* Breakpoint.cpp */; };
>>>> +		2660387E211CA98200329572 /* BreakpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2660387D211CA98200329572 /* BreakpointBase.cpp */; };
>>>> 		2689FFF113353DB600698AC0 /* BreakpointID.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0B10F1B83100F91463 /* BreakpointID.cpp */; };
>>>> 		2689FFF313353DB600698AC0 /* BreakpointIDList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E0C10F1B83100F91463 /* BreakpointIDList.cpp */; };
>>>> 		23E2E5321D903832006F38BB /* BreakpointIDTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23E2E52D1D90382B006F38BB /* BreakpointIDTest.cpp */; };
>>>> @@ -290,6 +291,7 @@
>>>> 		9A22A163135E30370024DDC3 /* EmulationStateARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A22A15F135E30370024DDC3 /* EmulationStateARM.cpp */; };
>>>> 		6B74D89B200696BB0074051B /* Environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 22DC561920064C9600A7E9E8 /* Environment.cpp */; };
>>>> 		2689003D13353E0400698AC0 /* Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7910F1B85900F91463 /* Event.cpp */; };
>>>> +		2660387A211CA90F00329572 /* ExceptionBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26603874211CA90E00329572 /* ExceptionBreakpoint.cpp */; };
>>>> 		268900EB13353E6F00698AC0 /* ExecutionContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3510F1B90C00F91463 /* ExecutionContext.cpp */; };
>>>> 		4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C88BC291BA3722B00AA0964 /* Expression.cpp */; };
>>>> 		49A1CAC51430E8DE00306AC9 /* ExpressionSourceCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A1CAC31430E8BD00306AC9 /* ExpressionSourceCode.cpp */; };
>>>> @@ -313,6 +315,7 @@
>>>> 		AF23B4DB19009C66003E2A58 /* FreeBSDSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */; };
>>>> 		268900D913353E6F00698AC0 /* FuncUnwinders.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */; };
>>>> 		268900D813353E6F00698AC0 /* Function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F1810F1B8EC00F91463 /* Function.cpp */; };
>>>> +		2660387C211CA90F00329572 /* FunctionBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26603877211CA90E00329572 /* FunctionBreakpoint.cpp */; };
>>>> 		4C2479BD1BA39295009C9A7B /* FunctionCaller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */; };
>>>> 		2374D7531D4BB2FF005C9575 /* GDBRemoteClientBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2374D74E1D4BB299005C9575 /* GDBRemoteClientBase.cpp */; };
>>>> 		23CB153A1D66DA9300EDDDE1 /* GDBRemoteClientBaseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2370A37D1D66C587000E7BE6 /* GDBRemoteClientBaseTest.cpp */; };
>>>> @@ -369,6 +372,7 @@
>>>> 		26BC179A18C7F2B300D2196D /* JITLoaderList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC179818C7F2B300D2196D /* JITLoaderList.cpp */; };
>>>> 		942829561A89614C00521B30 /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 942829551A89614C00521B30 /* JSON.cpp */; };
>>>> 		8C3BD9A01EF5D1FF0016C343 /* JSONTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD99F1EF5D1B50016C343 /* JSONTest.cpp */; };
>>>> +		2660387B211CA90F00329572 /* JSONUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26603875211CA90E00329572 /* JSONUtils.cpp */; };
>>>> 		6D0F61431C80AAAE00A4ECEE /* JavaASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61411C80AAAA00A4ECEE /* JavaASTContext.cpp */; };
>>>> 		6D0F61591C80AB3500A4ECEE /* JavaFormatterFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61511C80AB3000A4ECEE /* JavaFormatterFunctions.cpp */; };
>>>> 		6D0F615A1C80AB3900A4ECEE /* JavaLanguage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61531C80AB3000A4ECEE /* JavaLanguage.cpp */; };
>>>> @@ -376,9 +380,11 @@
>>>> 		6D0F614F1C80AB0C00A4ECEE /* JavaLanguageRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0F614B1C80AB0400A4ECEE /* JavaLanguageRuntime.h */; };
>>>> 		2668035C11601108008E1FE4 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; };
>>>> 		2669424D1A6DC32B0063BE93 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; };
>>>> +		26792623211CA42300EE1D10 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; };
>>>> 		26B42C4D1187ABA50079C8C8 /* LLDB.h in Headers */ = {isa = PBXBuildFile; fileRef = 26B42C4C1187ABA50079C8C8 /* LLDB.h */; settings = {ATTRIBUTES = (Public, ); }; };
>>>> 		943BDEFE1AA7B2F800789CE8 /* LLDBAssert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 943BDEFD1AA7B2F800789CE8 /* LLDBAssert.cpp */; };
>>>> 		6D762BEE1B1605D2006C929D /* LLDBServerUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D762BEC1B1605CD006C929D /* LLDBServerUtilities.cpp */; };
>>>> +		26F7619B211CBBB30044F6EA /* LLDBUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F76199211CBBB30044F6EA /* LLDBUtils.cpp */; };
>>>> 		2660AAB914622483003A9694 /* LLDBWrapPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */; settings = {COMPILER_FLAGS = "-Dregister="; }; };
>>>> 		AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AEB0E4581BD6E9F800B24093 /* LLVMUserExpression.cpp */; };
>>>> 		94B638531B8F8E6C004FE1E4 /* Language.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B638521B8F8E6C004FE1E4 /* Language.cpp */; };
>>>> @@ -487,9 +493,6 @@
>>>> 		8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; };
>>>> 		2689004313353E0400698AC0 /* Mangled.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8010F1B85900F91463 /* Mangled.cpp */; };
>>>> 		4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4F29D3CD21010F84003B549A /* MangledTest.cpp */; };
>>>> -		4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FBC04EE211A06820015A814 /* RichManglingContext.h */; };
>>>> -		4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */; };
>>>> -		4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */; };
>>>> 		4CD44CFC20B37C440003557C /* ManualDWARFIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */; };
>>>> 		49DCF702170E70120092F75E /* Materializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF700170E70120092F75E /* Materializer.cpp */; };
>>>> 		2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2690B3701381D5C300ECFBAE /* Memory.cpp */; };
>>>> @@ -708,6 +711,9 @@
>>>> 		23D065901D4A7BEE0008EDE6 /* RenderScriptRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D065841D4A7BDA0008EDE6 /* RenderScriptRuntime.cpp */; };
>>>> 		9485545A1DCBAE3B00345FF5 /* RenderScriptScriptGroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 948554591DCBAE3B00345FF5 /* RenderScriptScriptGroup.cpp */; };
>>>> 		23D065911D4A7BEE0008EDE6 /* RenderScriptx86ABIFixups.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D065861D4A7BDA0008EDE6 /* RenderScriptx86ABIFixups.cpp */; };
>>>> +		4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */; };
>>>> +		4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FBC04EE211A06820015A814 /* RichManglingContext.h */; };
>>>> +		4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */; };
>>>> 		26DE204511618ADA00A093E2 /* SBAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE204411618ADA00A093E2 /* SBAddress.cpp */; };
>>>> 		26DE204311618ACA00A093E2 /* SBAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = 26DE204211618ACA00A093E2 /* SBAddress.h */; settings = {ATTRIBUTES = (Public, ); }; };
>>>> 		254FBBA51A91670E00BD6378 /* SBAttachInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 254FBBA41A91670E00BD6378 /* SBAttachInfo.cpp */; };
>>>> @@ -858,6 +864,7 @@
>>>> 		23CB15451D66DA9300EDDDE1 /* SocketAddressTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2321F9391BDD332400BA9A93 /* SocketAddressTest.cpp */; };
>>>> 		23CB153B1D66DA9300EDDDE1 /* SocketTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2321F93A1BDD332400BA9A93 /* SocketTest.cpp */; };
>>>> 		232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */; };
>>>> +		26603879211CA90F00329572 /* SourceBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26603870211CA90D00329572 /* SourceBreakpoint.cpp */; };
>>>> 		2689004C13353E0400698AC0 /* SourceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8F10F1B85900F91463 /* SourceManager.cpp */; };
>>>> 		268900F313353E6F00698AC0 /* StackFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3810F1B90C00F91463 /* StackFrame.cpp */; };
>>>> 		268900F413353E6F00698AC0 /* StackFrameList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */; };
>>>> @@ -1002,6 +1009,7 @@
>>>> 		2654A6901E552ED500DA1013 /* VASprintf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2654A68F1E552ED500DA1013 /* VASprintf.cpp */; };
>>>> 		9A2057031F3A605200F6C293 /* VASprintfTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3D43C41F3150D200EB767C /* VASprintfTest.cpp */; };
>>>> 		AFC2DCF01E6E2FD200283714 /* VMRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFC2DCEF1E6E2FD200283714 /* VMRange.cpp */; };
>>>> +		26603878211CA90F00329572 /* VSCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2660386E211CA90D00329572 /* VSCode.cpp */; };
>>>> 		2689005613353E0400698AC0 /* Value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9910F1B85900F91463 /* Value.cpp */; };
>>>> 		2689005713353E0400698AC0 /* ValueObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */; };
>>>> 		94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94094C69163B6CD90083A547 /* ValueObjectCast.cpp */; };
>>>> @@ -1050,6 +1058,7 @@
>>>> 		2656BBC41AE073A800441749 /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2670F8111862B44A006B332C /* libncurses.dylib */; };
>>>> 		2670F8121862B44A006B332C /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2670F8111862B44A006B332C /* libncurses.dylib */; };
>>>> 		26780C611867C33D00234593 /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2670F8111862B44A006B332C /* libncurses.dylib */; };
>>>> +		26792622211CA41E00EE1D10 /* libncurses.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 26792621211CA41E00EE1D10 /* libncurses.tbd */; };
>>>> 		26680233115FD1A7008E1FE4 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
>>>> 		23CB154A1D66DA9300EDDDE1 /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2326CF4E1BDD687800A5CEAC /* libpanel.dylib */; };
>>>> 		260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
>>>> @@ -1074,6 +1083,7 @@
>>>> 		E769331E1A94D18100C73337 /* lldb-server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E769331D1A94D18100C73337 /* lldb-server.cpp */; };
>>>> 		26680214115FD12C008E1FE4 /* lldb-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 26BC7C2910F1B3BC00F91463 /* lldb-types.h */; settings = {ATTRIBUTES = (Public, ); }; };
>>>> 		94145431175E63B500284436 /* lldb-versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 94145430175D7FDE00284436 /* lldb-versioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
>>>> +		2679261E211CA3F200EE1D10 /* lldb-vscode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26792619211CA3E100EE1D10 /* lldb-vscode.cpp */; };
>>>> 		AF90106515AB7D3600FF120D /* lldb.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = AF90106315AB7C5700FF120D /* lldb.1 */; };
>>>> 		2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E7410F1B85900F91463 /* lldb.cpp */; };
>>>> 		AF415AE71D949E4400FCE0D4 /* x86AssemblyInspectionEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF415AE51D949E4400FCE0D4 /* x86AssemblyInspectionEngine.cpp */; };
>>>> @@ -1123,6 +1133,13 @@
>>>> 			remoteGlobalIDString = 26680206115FD0ED008E1FE4;
>>>> 			remoteInfo = LLDB;
>>>> 		};
>>>> +		2679261F211CA40700EE1D10 /* PBXContainerItemProxy */ = {
>>>> +			isa = PBXContainerItemProxy;
>>>> +			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
>>>> +			proxyType = 1;
>>>> +			remoteGlobalIDString = 26680206115FD0ED008E1FE4;
>>>> +			remoteInfo = LLDB;
>>>> +		};
>>>> 		2687EACA1508115000DD8C2E /* PBXContainerItemProxy */ = {
>>>> 			isa = PBXContainerItemProxy;
>>>> 			containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
>>>> @@ -1264,6 +1281,15 @@
>>>> 			name = "Copy Files";
>>>> 			runOnlyForDeploymentPostprocessing = 1;
>>>> 		};
>>>> +		2679260A211CA3AC00EE1D10 /* CopyFiles */ = {
>>>> +			isa = PBXCopyFilesBuildPhase;
>>>> +			buildActionMask = 2147483647;
>>>> +			dstPath = /usr/share/man/man1/;
>>>> +			dstSubfolderSpec = 0;
>>>> +			files = (
>>>> +			);
>>>> +			runOnlyForDeploymentPostprocessing = 1;
>>>> +		};
>>>> 		940B04E31A89875C0045D5F7 /* CopyFiles */ = {
>>>> 			isa = PBXCopyFilesBuildPhase;
>>>> 			buildActionMask = 2147483647;
>>>> @@ -1427,6 +1453,8 @@
>>>> 		49DEF1201CD7BD90006A7C7D /* BlockPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BlockPointer.h; path = Language/CPlusPlus/BlockPointer.h; sourceTree = "<group>"; };
>>>> 		26BC7E0A10F1B83100F91463 /* Breakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Breakpoint.cpp; path = source/Breakpoint/Breakpoint.cpp; sourceTree = "<group>"; };
>>>> 		26BC7CEE10F1B71400F91463 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Breakpoint.h; path = include/lldb/Breakpoint/Breakpoint.h; sourceTree = "<group>"; };
>>>> +		2660387D211CA98200329572 /* BreakpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointBase.cpp; path = "tools/lldb-vscode/BreakpointBase.cpp"; sourceTree = "<group>"; };
>>>> +		26603872211CA90D00329572 /* BreakpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointBase.h; path = "tools/lldb-vscode/BreakpointBase.h"; sourceTree = "<group>"; };
>>>> 		26BC7E0B10F1B83100F91463 /* BreakpointID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointID.cpp; path = source/Breakpoint/BreakpointID.cpp; sourceTree = "<group>"; };
>>>> 		26BC7CEF10F1B71400F91463 /* BreakpointID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointID.h; path = include/lldb/Breakpoint/BreakpointID.h; sourceTree = "<group>"; };
>>>> 		26BC7E0C10F1B83100F91463 /* BreakpointIDList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointIDList.cpp; path = source/Breakpoint/BreakpointIDList.cpp; sourceTree = "<group>"; };
>>>> @@ -1497,6 +1525,7 @@
>>>> 		23E2E5191D9036F2006F38BB /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
>>>> 		23E2E5361D9048FB006F38BB /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
>>>> 		2669415B1A6DC2AB0063BE93 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = "tools/lldb-mi/CMakeLists.txt"; sourceTree = SOURCE_ROOT; };
>>>> +		26792617211CA3E100EE1D10 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = "tools/lldb-vscode/CMakeLists.txt"; sourceTree = "<group>"; };
>>>> 		9A1890311F47D5D400394BCA /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = TestingSupport/CMakeLists.txt; sourceTree = "<group>"; };
>>>> 		4CB443BC1249920C00C13DC2 /* CPPLanguageRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CPPLanguageRuntime.cpp; path = source/Target/CPPLanguageRuntime.cpp; sourceTree = "<group>"; };
>>>> 		4CB443BB1249920C00C13DC2 /* CPPLanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CPPLanguageRuntime.h; path = include/lldb/Target/CPPLanguageRuntime.h; sourceTree = "<group>"; };
>>>> @@ -1796,6 +1825,8 @@
>>>> 		6B74D89C2006972D0074051B /* Environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Environment.h; path = include/lldb/Utility/Environment.h; sourceTree = "<group>"; };
>>>> 		26BC7E7910F1B85900F91463 /* Event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Event.cpp; path = source/Core/Event.cpp; sourceTree = "<group>"; };
>>>> 		26BC7D6110F1B77400F91463 /* Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Event.h; path = include/lldb/Core/Event.h; sourceTree = "<group>"; };
>>>> +		26603874211CA90E00329572 /* ExceptionBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExceptionBreakpoint.cpp; path = "tools/lldb-vscode/ExceptionBreakpoint.cpp"; sourceTree = "<group>"; };
>>>> +		26603873211CA90E00329572 /* ExceptionBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExceptionBreakpoint.h; path = "tools/lldb-vscode/ExceptionBreakpoint.h"; sourceTree = "<group>"; };
>>>> 		26BC7F3510F1B90C00F91463 /* ExecutionContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExecutionContext.cpp; path = source/Target/ExecutionContext.cpp; sourceTree = "<group>"; };
>>>> 		26BC7DF210F1B81A00F91463 /* ExecutionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionContext.h; path = include/lldb/Target/ExecutionContext.h; sourceTree = "<group>"; };
>>>> 		26DAFD9711529BC7005A394E /* ExecutionContextScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExecutionContextScope.h; path = include/lldb/Target/ExecutionContextScope.h; sourceTree = "<group>"; };
>>>> @@ -1847,6 +1878,8 @@
>>>> 		269FF07D12494F7D00225026 /* FuncUnwinders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FuncUnwinders.h; path = include/lldb/Symbol/FuncUnwinders.h; sourceTree = "<group>"; };
>>>> 		26BC7F1810F1B8EC00F91463 /* Function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Function.cpp; path = source/Symbol/Function.cpp; sourceTree = "<group>"; };
>>>> 		26BC7C5A10F1B6E900F91463 /* Function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Function.h; path = include/lldb/Symbol/Function.h; sourceTree = "<group>"; };
>>>> +		26603877211CA90E00329572 /* FunctionBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FunctionBreakpoint.cpp; path = "tools/lldb-vscode/FunctionBreakpoint.cpp"; sourceTree = "<group>"; };
>>>> +		26603871211CA90D00329572 /* FunctionBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FunctionBreakpoint.h; path = "tools/lldb-vscode/FunctionBreakpoint.h"; sourceTree = "<group>"; };
>>>> 		4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FunctionCaller.cpp; path = source/Expression/FunctionCaller.cpp; sourceTree = "<group>"; };
>>>> 		4C00832D1B9A58A700D5CF24 /* FunctionCaller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FunctionCaller.h; path = include/lldb/Expression/FunctionCaller.h; sourceTree = "<group>"; };
>>>> 		2374D74E1D4BB299005C9575 /* GDBRemoteClientBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteClientBase.cpp; sourceTree = "<group>"; };
>>>> @@ -1977,6 +2010,8 @@
>>>> 		942829551A89614C00521B30 /* JSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSON.cpp; path = source/Utility/JSON.cpp; sourceTree = "<group>"; };
>>>> 		942829541A89614000521B30 /* JSON.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JSON.h; path = include/lldb/Utility/JSON.h; sourceTree = "<group>"; };
>>>> 		8C3BD99F1EF5D1B50016C343 /* JSONTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JSONTest.cpp; sourceTree = "<group>"; };
>>>> +		26603875211CA90E00329572 /* JSONUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSONUtils.cpp; path = "tools/lldb-vscode/JSONUtils.cpp"; sourceTree = "<group>"; };
>>>> +		26603876211CA90E00329572 /* JSONUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONUtils.h; path = "tools/lldb-vscode/JSONUtils.h"; sourceTree = "<group>"; };
>>>> 		6D0F61411C80AAAA00A4ECEE /* JavaASTContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JavaASTContext.cpp; path = source/Symbol/JavaASTContext.cpp; sourceTree = "<group>"; };
>>>> 		6D0F613D1C80AA8900A4ECEE /* JavaASTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JavaASTContext.h; path = include/lldb/Symbol/JavaASTContext.h; sourceTree = "<group>"; };
>>>> 		6D0F61511C80AB3000A4ECEE /* JavaFormatterFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JavaFormatterFunctions.cpp; path = Language/Java/JavaFormatterFunctions.cpp; sourceTree = "<group>"; };
>>>> @@ -1993,6 +2028,8 @@
>>>> 		6D762BEC1B1605CD006C929D /* LLDBServerUtilities.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LLDBServerUtilities.cpp; path = "tools/lldb-server/LLDBServerUtilities.cpp"; sourceTree = "<group>"; };
>>>> 		6D762BED1B1605CD006C929D /* LLDBServerUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LLDBServerUtilities.h; path = "tools/lldb-server/LLDBServerUtilities.h"; sourceTree = "<group>"; };
>>>> 		2361029A1CF38A2B00B8E0B9 /* LLDBStandalone.cmake */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LLDBStandalone.cmake; sourceTree = "<group>"; };
>>>> +		26F76199211CBBB30044F6EA /* LLDBUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLDBUtils.cpp; path = "tools/lldb-vscode/LLDBUtils.cpp"; sourceTree = "<group>"; };
>>>> +		26F7619A211CBBB30044F6EA /* LLDBUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLDBUtils.h; path = "tools/lldb-vscode/LLDBUtils.h"; sourceTree = "<group>"; };
>>>> 		26A4EEB511682AAC007A372A /* LLDBWrapPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = LLDBWrapPython.cpp; sourceTree = BUILT_PRODUCTS_DIR; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
>>>> 		AEB0E4581BD6E9F800B24093 /* LLVMUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLVMUserExpression.cpp; path = source/Expression/LLVMUserExpression.cpp; sourceTree = "<group>"; };
>>>> 		AEB0E45A1BD6EA1400B24093 /* LLVMUserExpression.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LLVMUserExpression.h; path = include/lldb/Expression/LLVMUserExpression.h; sourceTree = "<group>"; };
>>>> @@ -2199,9 +2236,6 @@
>>>> 		26BC7E8010F1B85900F91463 /* Mangled.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mangled.cpp; path = source/Core/Mangled.cpp; sourceTree = "<group>"; };
>>>> 		26BC7D6910F1B77400F91463 /* Mangled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mangled.h; path = include/lldb/Core/Mangled.h; sourceTree = "<group>"; };
>>>> 		4F29D3CD21010F84003B549A /* MangledTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MangledTest.cpp; sourceTree = "<group>"; };
>>>> -		4FBC04EE211A06820015A814 /* RichManglingContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RichManglingContext.h; path = include/lldb/Core/RichManglingContext.h; sourceTree = "<group>"; };
>>>> -		4FBC04EC211A06200015A814 /* RichManglingContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RichManglingContext.cpp; path = source/Core/RichManglingContext.cpp; sourceTree = "<group>"; };
>>>> -		4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RichManglingContextTest.cpp; sourceTree = "<group>"; };
>>>> 		4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ManualDWARFIndex.cpp; sourceTree = "<group>"; };
>>>> 		4CD44D0020B37C580003557C /* ManualDWARFIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ManualDWARFIndex.h; sourceTree = "<group>"; };
>>>> 		2682100C143A59AE004BCF2D /* MappedHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MappedHash.h; path = include/lldb/Core/MappedHash.h; sourceTree = "<group>"; };
>>>> @@ -2638,6 +2672,9 @@
>>>> 		948554581DCBAE3200345FF5 /* RenderScriptScriptGroup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RenderScriptScriptGroup.h; sourceTree = "<group>"; };
>>>> 		23D065861D4A7BDA0008EDE6 /* RenderScriptx86ABIFixups.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderScriptx86ABIFixups.cpp; sourceTree = "<group>"; };
>>>> 		23D065871D4A7BDA0008EDE6 /* RenderScriptx86ABIFixups.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderScriptx86ABIFixups.h; sourceTree = "<group>"; };
>>>> +		4FBC04EC211A06200015A814 /* RichManglingContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RichManglingContext.cpp; path = source/Core/RichManglingContext.cpp; sourceTree = "<group>"; };
>>>> +		4FBC04EE211A06820015A814 /* RichManglingContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RichManglingContext.h; path = include/lldb/Core/RichManglingContext.h; sourceTree = "<group>"; };
>>>> +		4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RichManglingContextTest.cpp; sourceTree = "<group>"; };
>>>> 		26DE204411618ADA00A093E2 /* SBAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBAddress.cpp; path = source/API/SBAddress.cpp; sourceTree = "<group>"; };
>>>> 		26DE204211618ACA00A093E2 /* SBAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBAddress.h; path = include/lldb/API/SBAddress.h; sourceTree = "<group>"; };
>>>> 		2611FEEF142D83060017FEA3 /* SBAddress.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBAddress.i; sourceTree = "<group>"; };
>>>> @@ -2867,8 +2904,11 @@
>>>> 		2321F93A1BDD332400BA9A93 /* SocketTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SocketTest.cpp; sourceTree = "<group>"; };
>>>> 		232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SoftwareBreakpoint.cpp; path = source/Host/common/SoftwareBreakpoint.cpp; sourceTree = "<group>"; };
>>>> 		267A47F21B14115A0021A5BC /* SoftwareBreakpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SoftwareBreakpoint.h; path = include/lldb/Host/common/SoftwareBreakpoint.h; sourceTree = "<group>"; };
>>>> +		26603870211CA90D00329572 /* SourceBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SourceBreakpoint.cpp; path = "tools/lldb-vscode/SourceBreakpoint.cpp"; sourceTree = "<group>"; };
>>>> +		2660386D211CA90C00329572 /* SourceBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SourceBreakpoint.h; path = "tools/lldb-vscode/SourceBreakpoint.h"; sourceTree = "<group>"; };
>>>> 		26BC7E8F10F1B85900F91463 /* SourceManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SourceManager.cpp; path = source/Core/SourceManager.cpp; sourceTree = "<group>"; };
>>>> 		26BC7D7610F1B77400F91463 /* SourceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SourceManager.h; path = include/lldb/Core/SourceManager.h; sourceTree = "<group>"; };
>>>> +		26F76198211CB8870044F6EA /* SourceReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SourceReference.h; path = "tools/lldb-vscode/SourceReference.h"; sourceTree = "<group>"; };
>>>> 		26BC7F3810F1B90C00F91463 /* StackFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrame.cpp; path = source/Target/StackFrame.cpp; sourceTree = "<group>"; };
>>>> 		26BC7DF510F1B81A00F91463 /* StackFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackFrame.h; path = include/lldb/Target/StackFrame.h; sourceTree = "<group>"; };
>>>> 		26BC7F3910F1B90C00F91463 /* StackFrameList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StackFrameList.cpp; path = source/Target/StackFrameList.cpp; sourceTree = "<group>"; };
>>>> @@ -3135,6 +3175,9 @@
>>>> 		9A3D43C41F3150D200EB767C /* VASprintfTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VASprintfTest.cpp; sourceTree = "<group>"; };
>>>> 		AFC2DCEF1E6E2FD200283714 /* VMRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VMRange.cpp; path = source/Utility/VMRange.cpp; sourceTree = "<group>"; };
>>>> 		AFC2DCF11E6E2FDA00283714 /* VMRange.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VMRange.h; path = include/lldb/Utility/VMRange.h; sourceTree = "<group>"; };
>>>> +		2660386E211CA90D00329572 /* VSCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VSCode.cpp; path = "tools/lldb-vscode/VSCode.cpp"; sourceTree = "<group>"; };
>>>> +		2660386F211CA90D00329572 /* VSCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VSCode.h; path = "tools/lldb-vscode/VSCode.h"; sourceTree = "<group>"; };
>>>> +		26F7619C211CDD700044F6EA /* VSCodeForward.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VSCodeForward.h; path = "tools/lldb-vscode/VSCodeForward.h"; sourceTree = "<group>"; };
>>>> 		26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = "<group>"; };
>>>> 		26BC7D8110F1B77400F91463 /* Value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Value.h; path = include/lldb/Core/Value.h; sourceTree = "<group>"; };
>>>> 		26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
>>>> @@ -3217,6 +3260,7 @@
>>>> 		2326CF471BDD67C100A5CEAC /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = ../../../../../../usr/lib/libncurses.dylib; sourceTree = "<group>"; };
>>>> 		239481851C59EBDD00DF7168 /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = ../../../../../usr/lib/libncurses.dylib; sourceTree = "<group>"; };
>>>> 		2670F8111862B44A006B332C /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = /usr/lib/libncurses.dylib; sourceTree = "<absolute>"; };
>>>> +		26792621211CA41E00EE1D10 /* libncurses.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libncurses.tbd; path = usr/lib/libncurses.tbd; sourceTree = SDKROOT; };
>>>> 		26F5C37410F3F61B009D5894 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = /usr/lib/libobjc.dylib; sourceTree = "<absolute>"; };
>>>> 		2326CF4E1BDD687800A5CEAC /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = ../../../../../../usr/lib/libpanel.dylib; sourceTree = "<group>"; };
>>>> 		260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = "<absolute>"; };
>>>> @@ -3250,11 +3294,15 @@
>>>> 		E769331D1A94D18100C73337 /* lldb-server.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lldb-server.cpp"; path = "tools/lldb-server/lldb-server.cpp"; sourceTree = "<group>"; };
>>>> 		26BC7C2910F1B3BC00F91463 /* lldb-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-types.h"; path = "include/lldb/lldb-types.h"; sourceTree = "<group>"; };
>>>> 		94145430175D7FDE00284436 /* lldb-versioning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-versioning.h"; path = "include/lldb/lldb-versioning.h"; sourceTree = "<group>"; };
>>>> +		2679260C211CA3AC00EE1D10 /* lldb-vscode */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "lldb-vscode"; sourceTree = BUILT_PRODUCTS_DIR; };
>>>> +		26792618211CA3E100EE1D10 /* lldb-vscode-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "lldb-vscode-Info.plist"; path = "tools/lldb-vscode/lldb-vscode-Info.plist"; sourceTree = "<group>"; };
>>>> +		26792619211CA3E100EE1D10 /* lldb-vscode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lldb-vscode.cpp"; path = "tools/lldb-vscode/lldb-vscode.cpp"; sourceTree = "<group>"; };
>>>> 		23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-x86-register-enums.h"; path = "Utility/lldb-x86-register-enums.h"; sourceTree = "<group>"; };
>>>> 		AF90106315AB7C5700FF120D /* lldb.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = lldb.1; path = docs/lldb.1; sourceTree = "<group>"; };
>>>> 		26BC7E7410F1B85900F91463 /* lldb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lldb.cpp; path = source/lldb.cpp; sourceTree = "<group>"; };
>>>> 		2669605E1199F4230075C61A /* lldb.swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = lldb.swig; sourceTree = "<group>"; };
>>>> 		94E367CC140C4EC4001C7A5A /* modify-python-lldb.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = "modify-python-lldb.py"; sourceTree = "<group>"; };
>>>> +		26792616211CA3E100EE1D10 /* package.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = package.json; path = "tools/lldb-vscode/package.json"; sourceTree = "<group>"; };
>>>> 		9A48A3A7124AAA5A00922451 /* python-extensions.swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "python-extensions.swig"; sourceTree = "<group>"; };
>>>> 		944DC3481774C99000D7D884 /* python-swigsafecast.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-swigsafecast.swig"; sourceTree = "<group>"; };
>>>> 		94E367CE140C4EEA001C7A5A /* python-typemaps.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-typemaps.swig"; sourceTree = "<group>"; };
>>>> @@ -3322,6 +3370,15 @@
>>>> 			);
>>>> 			runOnlyForDeploymentPostprocessing = 0;
>>>> 		};
>>>> +		26792609211CA3AC00EE1D10 /* Frameworks */ = {
>>>> +			isa = PBXFrameworksBuildPhase;
>>>> +			buildActionMask = 2147483647;
>>>> +			files = (
>>>> +				26792623211CA42300EE1D10 /* LLDB.framework in Frameworks */,
>>>> +				26792622211CA41E00EE1D10 /* libncurses.tbd in Frameworks */,
>>>> +			);
>>>> +			runOnlyForDeploymentPostprocessing = 0;
>>>> +		};
>>>> 		2689FFC713353D7A00698AC0 /* Frameworks */ = {
>>>> 			isa = PBXFrameworksBuildPhase;
>>>> 			buildActionMask = 2147483647;
>>>> @@ -3437,6 +3494,7 @@
>>>> 				942829C01A89835300521B30 /* lldb-argdumper */,
>>>> 				239504D41BDD451400963CEA /* lldb-gtest */,
>>>> 				23CB15561D66DA9300EDDDE1 /* lldb-gtest */,
>>>> +				2679260C211CA3AC00EE1D10 /* lldb-vscode */,
>>>> 			);
>>>> 			name = Products;
>>>> 			sourceTree = "<group>";
>>>> @@ -3672,6 +3730,7 @@
>>>> 		23CB14E21D66CA2200EDDDE1 /* Frameworks */ = {
>>>> 			isa = PBXGroup;
>>>> 			children = (
>>>> +				26792621211CA41E00EE1D10 /* libncurses.tbd */,
>>>> 				23CB14E31D66CA2200EDDDE1 /* libxml2.2.dylib */,
>>>> 			);
>>>> 			name = Frameworks;
>>>> @@ -4469,6 +4528,33 @@
>>>> 			path = OperatingSystem;
>>>> 			sourceTree = "<group>";
>>>> 		};
>>>> +		26792615211CA3C100EE1D10 /* lldb-vscode */ = {
>>>> +			isa = PBXGroup;
>>>> +			children = (
>>>> +				26792617211CA3E100EE1D10 /* CMakeLists.txt */,
>>>> +				26792618211CA3E100EE1D10 /* lldb-vscode-Info.plist */,
>>>> +				26792619211CA3E100EE1D10 /* lldb-vscode.cpp */,
>>>> +				26792616211CA3E100EE1D10 /* package.json */,
>>>> +				2660387D211CA98200329572 /* BreakpointBase.cpp */,
>>>> +				26603872211CA90D00329572 /* BreakpointBase.h */,
>>>> +				26603874211CA90E00329572 /* ExceptionBreakpoint.cpp */,
>>>> +				26603873211CA90E00329572 /* ExceptionBreakpoint.h */,
>>>> +				26603877211CA90E00329572 /* FunctionBreakpoint.cpp */,
>>>> +				26603871211CA90D00329572 /* FunctionBreakpoint.h */,
>>>> +				26603875211CA90E00329572 /* JSONUtils.cpp */,
>>>> +				26603876211CA90E00329572 /* JSONUtils.h */,
>>>> +				26F76199211CBBB30044F6EA /* LLDBUtils.cpp */,
>>>> +				26F7619A211CBBB30044F6EA /* LLDBUtils.h */,
>>>> +				26603870211CA90D00329572 /* SourceBreakpoint.cpp */,
>>>> +				2660386D211CA90C00329572 /* SourceBreakpoint.h */,
>>>> +				26F76198211CB8870044F6EA /* SourceReference.h */,
>>>> +				2660386E211CA90D00329572 /* VSCode.cpp */,
>>>> +				2660386F211CA90D00329572 /* VSCode.h */,
>>>> +				26F7619C211CDD700044F6EA /* VSCodeForward.h */,
>>>> +			);
>>>> +			name = "lldb-vscode";
>>>> +			sourceTree = "<group>";
>>>> +		};
>>>> 		267F68461CC02DED0086832B /* SysV-s390x */ = {
>>>> 			isa = PBXGroup;
>>>> 			children = (
>>>> @@ -5844,6 +5930,7 @@
>>>> 			isa = PBXGroup;
>>>> 			children = (
>>>> 				E769331B1A94D10E00C73337 /* lldb-server */,
>>>> +				26792615211CA3C100EE1D10 /* lldb-vscode */,
>>>> 				942829BA1A89830900521B30 /* argdumper */,
>>>> 				26579F55126A255E0007C5CB /* darwin-debug */,
>>>> 				265E9BE0115C2B8500D0DCCB /* debugserver */,
>>>> @@ -7098,6 +7185,24 @@
>>>> 			productReference = 26680207115FD0ED008E1FE4 /* LLDB.framework */;
>>>> 			productType = "com.apple.product-type.framework";
>>>> 		};
>>>> +		2679260B211CA3AC00EE1D10 /* lldb-vscode */ = {
>>>> +			isa = PBXNativeTarget;
>>>> +			buildConfigurationList = 26792614211CA3AD00EE1D10 /* Build configuration list for PBXNativeTarget "lldb-vscode" */;
>>>> +			buildPhases = (
>>>> +				26792608211CA3AC00EE1D10 /* Sources */,
>>>> +				26792609211CA3AC00EE1D10 /* Frameworks */,
>>>> +				2679260A211CA3AC00EE1D10 /* CopyFiles */,
>>>> +			);
>>>> +			buildRules = (
>>>> +			);
>>>> +			dependencies = (
>>>> +				26792620211CA40700EE1D10 /* PBXTargetDependency */,
>>>> +			);
>>>> +			name = "lldb-vscode";
>>>> +			productName = "lldb-vscode";
>>>> +			productReference = 2679260C211CA3AC00EE1D10 /* lldb-vscode */;
>>>> +			productType = "com.apple.product-type.tool";
>>>> +		};
>>>> 		2689FFC913353D7A00698AC0 /* lldb-core */ = {
>>>> 			isa = PBXNativeTarget;
>>>> 			buildConfigurationList = 2689FFD813353D7A00698AC0 /* Build configuration list for PBXNativeTarget "lldb-core" */;
>>>> @@ -7202,6 +7307,9 @@
>>>> 					239504D31BDD451400963CEA = {
>>>> 						CreatedOnToolsVersion = 7.1;
>>>> 					};
>>>> +					2679260B211CA3AC00EE1D10 = {
>>>> +						CreatedOnToolsVersion = 9.4.1;
>>>> +					};
>>>> 					2690CD161A6DC0D000E717C8 = {
>>>> 						CreatedOnToolsVersion = 6.3;
>>>> 					};
>>>> @@ -7242,6 +7350,7 @@
>>>> 				2687EAC51508110B00DD8C2E /* install-headers */,
>>>> 				2690CD161A6DC0D000E717C8 /* lldb-mi */,
>>>> 				942829BF1A89835300521B30 /* lldb-argdumper */,
>>>> +				2679260B211CA3AC00EE1D10 /* lldb-vscode */,
>>>> 			);
>>>> 		};
>>>> /* End PBXProject section */
>>>> @@ -7588,6 +7697,21 @@
>>>> 			);
>>>> 			runOnlyForDeploymentPostprocessing = 0;
>>>> 		};
>>>> +		26792608211CA3AC00EE1D10 /* Sources */ = {
>>>> +			isa = PBXSourcesBuildPhase;
>>>> +			buildActionMask = 2147483647;
>>>> +			files = (
>>>> +				2679261E211CA3F200EE1D10 /* lldb-vscode.cpp in Sources */,
>>>> +				2660387E211CA98200329572 /* BreakpointBase.cpp in Sources */,
>>>> +				26603879211CA90F00329572 /* SourceBreakpoint.cpp in Sources */,
>>>> +				2660387A211CA90F00329572 /* ExceptionBreakpoint.cpp in Sources */,
>>>> +				2660387B211CA90F00329572 /* JSONUtils.cpp in Sources */,
>>>> +				26F7619B211CBBB30044F6EA /* LLDBUtils.cpp in Sources */,
>>>> +				2660387C211CA90F00329572 /* FunctionBreakpoint.cpp in Sources */,
>>>> +				26603878211CA90F00329572 /* VSCode.cpp in Sources */,
>>>> +			);
>>>> +			runOnlyForDeploymentPostprocessing = 0;
>>>> +		};
>>>> 		2689FFC613353D7A00698AC0 /* Sources */ = {
>>>> 			isa = PBXSourcesBuildPhase;
>>>> 			buildActionMask = 2147483647;
>>>> @@ -8384,6 +8508,11 @@
>>>> 			target = 26680206115FD0ED008E1FE4 /* LLDB */;
>>>> 			targetProxy = 266803611160110D008E1FE4 /* PBXContainerItemProxy */;
>>>> 		};
>>>> +		26792620211CA40700EE1D10 /* PBXTargetDependency */ = {
>>>> +			isa = PBXTargetDependency;
>>>> +			target = 26680206115FD0ED008E1FE4 /* LLDB */;
>>>> +			targetProxy = 2679261F211CA40700EE1D10 /* PBXContainerItemProxy */;
>>>> +		};
>>>> 		2687EACB1508115000DD8C2E /* PBXTargetDependency */ = {
>>>> 			isa = PBXTargetDependency;
>>>> 			target = 2687EAC51508110B00DD8C2E /* install-headers */;
>>>> @@ -9273,6 +9402,212 @@
>>>> 			};
>>>> 			name = Release;
>>>> 		};
>>>> +		26792610211CA3AD00EE1D10 /* Debug */ = {
>>>> +			isa = XCBuildConfiguration;
>>>> +			buildSettings = {
>>>> +				CLANG_ANALYZER_NONNULL = YES;
>>>> +				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
>>>> +				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
>>>> +				CLANG_ENABLE_MODULES = YES;
>>>> +				CLANG_ENABLE_OBJC_ARC = YES;
>>>> +				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
>>>> +				CLANG_WARN_COMMA = YES;
>>>> +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
>>>> +				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
>>>> +				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
>>>> +				CLANG_WARN_INFINITE_RECURSION = YES;
>>>> +				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
>>>> +				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
>>>> +				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
>>>> +				CLANG_WARN_STRICT_PROTOTYPES = YES;
>>>> +				CLANG_WARN_SUSPICIOUS_MOVE = YES;
>>>> +				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
>>>> +				CURRENT_PROJECT_VERSION = 360.99.0;
>>>> +				GCC_C_LANGUAGE_STANDARD = gnu99;
>>>> +				GCC_DYNAMIC_NO_PIC = NO;
>>>> +				GCC_PREPROCESSOR_DEFINITIONS = (
>>>> +					"DEBUG=1",
>>>> +					"$(inherited)",
>>>> +				);
>>>> +				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
>>>> +				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
>>>> +				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
>>>> +				INSTALL_PATH = "$(LLDB_TOOLS_INSTALL_DIR)";
>>>> +				MTL_ENABLE_DEBUG_INFO = YES;
>>>> +				OTHER_LDFLAGS = (
>>>> +					"-sectcreate",
>>>> +					__TEXT,
>>>> +					__info_plist,
>>>> +					"$(PROJECT_DIR)/tools/lldb-vscode/lldb-vscode-Info.plist",
>>>> +					"-Wl,-rpath, at loader_path/",
>>>> +					"-filelist",
>>>> +					"$(LLVM_BUILD_DIR)/archives.txt",
>>>> +				);
>>>> +				PRODUCT_NAME = "$(TARGET_NAME)";
>>>> +				SDKROOT = macosx;
>>>> +				USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source $(LLVM_SOURCE_DIR)/include $(LLVM_SOURCE_DIR)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/lib/Target/ARM";
>>>> +				VERSIONING_SYSTEM = "apple-generic";
>>>> +			};
>>>> +			name = Debug;
>>>> +		};
>>>> +		26792611211CA3AD00EE1D10 /* DebugClang */ = {
>>>> +			isa = XCBuildConfiguration;
>>>> +			buildSettings = {
>>>> +				CLANG_ANALYZER_NONNULL = YES;
>>>> +				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
>>>> +				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
>>>> +				CLANG_ENABLE_MODULES = YES;
>>>> +				CLANG_ENABLE_OBJC_ARC = YES;
>>>> +				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
>>>> +				CLANG_WARN_COMMA = YES;
>>>> +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
>>>> +				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
>>>> +				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
>>>> +				CLANG_WARN_INFINITE_RECURSION = YES;
>>>> +				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
>>>> +				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
>>>> +				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
>>>> +				CLANG_WARN_STRICT_PROTOTYPES = YES;
>>>> +				CLANG_WARN_SUSPICIOUS_MOVE = YES;
>>>> +				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
>>>> +				CURRENT_PROJECT_VERSION = 360.99.0;
>>>> +				GCC_C_LANGUAGE_STANDARD = gnu99;
>>>> +				GCC_DYNAMIC_NO_PIC = NO;
>>>> +				GCC_PREPROCESSOR_DEFINITIONS = (
>>>> +					"DEBUG=1",
>>>> +					"$(inherited)",
>>>> +				);
>>>> +				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
>>>> +				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
>>>> +				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
>>>> +				INSTALL_PATH = "$(LLDB_TOOLS_INSTALL_DIR)";
>>>> +				MTL_ENABLE_DEBUG_INFO = YES;
>>>> +				OTHER_LDFLAGS = (
>>>> +					"-sectcreate",
>>>> +					__TEXT,
>>>> +					__info_plist,
>>>> +					"$(PROJECT_DIR)/tools/lldb-vscode/lldb-vscode-Info.plist",
>>>> +					"-Wl,-rpath, at loader_path/",
>>>> +					"-filelist",
>>>> +					"$(LLVM_BUILD_DIR)/archives.txt",
>>>> +				);
>>>> +				PRODUCT_NAME = "$(TARGET_NAME)";
>>>> +				SDKROOT = macosx;
>>>> +				USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source $(LLVM_SOURCE_DIR)/include $(LLVM_SOURCE_DIR)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/lib/Target/ARM";
>>>> +				VERSIONING_SYSTEM = "apple-generic";
>>>> +			};
>>>> +			name = DebugClang;
>>>> +		};
>>>> +		26792612211CA3AD00EE1D10 /* Release */ = {
>>>> +			isa = XCBuildConfiguration;
>>>> +			buildSettings = {
>>>> +				CLANG_ANALYZER_NONNULL = YES;
>>>> +				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
>>>> +				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
>>>> +				CLANG_ENABLE_MODULES = YES;
>>>> +				CLANG_ENABLE_OBJC_ARC = YES;
>>>> +				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
>>>> +				CLANG_WARN_COMMA = YES;
>>>> +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
>>>> +				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
>>>> +				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
>>>> +				CLANG_WARN_INFINITE_RECURSION = YES;
>>>> +				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
>>>> +				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
>>>> +				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
>>>> +				CLANG_WARN_STRICT_PROTOTYPES = YES;
>>>> +				CLANG_WARN_SUSPICIOUS_MOVE = YES;
>>>> +				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
>>>> +				CURRENT_PROJECT_VERSION = 360.99.0;
>>>> +				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
>>>> +				ENABLE_NS_ASSERTIONS = NO;
>>>> +				GCC_C_LANGUAGE_STANDARD = gnu99;
>>>> +				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
>>>> +				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
>>>> +				INSTALL_PATH = "$(LLDB_TOOLS_INSTALL_DIR)";
>>>> +				MTL_ENABLE_DEBUG_INFO = NO;
>>>> +				OTHER_LDFLAGS = (
>>>> +					"-sectcreate",
>>>> +					__TEXT,
>>>> +					__info_plist,
>>>> +					"$(PROJECT_DIR)/tools/lldb-vscode/lldb-vscode-Info.plist",
>>>> +					"-Wl,-rpath, at loader_path/",
>>>> +					"-filelist",
>>>> +					"$(LLVM_BUILD_DIR)/archives.txt",
>>>> +				);
>>>> +				PRODUCT_NAME = "$(TARGET_NAME)";
>>>> +				SDKROOT = macosx;
>>>> +				USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source $(LLVM_SOURCE_DIR)/include $(LLVM_SOURCE_DIR)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/lib/Target/ARM";
>>>> +				VERSIONING_SYSTEM = "apple-generic";
>>>> +			};
>>>> +			name = Release;
>>>> +		};
>>>> +		26792613211CA3AD00EE1D10 /* BuildAndIntegration */ = {
>>>> +			isa = XCBuildConfiguration;
>>>> +			buildSettings = {
>>>> +				CLANG_ANALYZER_NONNULL = YES;
>>>> +				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
>>>> +				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
>>>> +				CLANG_ENABLE_MODULES = YES;
>>>> +				CLANG_ENABLE_OBJC_ARC = YES;
>>>> +				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
>>>> +				CLANG_WARN_COMMA = YES;
>>>> +				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
>>>> +				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
>>>> +				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
>>>> +				CLANG_WARN_INFINITE_RECURSION = YES;
>>>> +				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
>>>> +				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
>>>> +				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
>>>> +				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
>>>> +				CLANG_WARN_STRICT_PROTOTYPES = YES;
>>>> +				CLANG_WARN_SUSPICIOUS_MOVE = YES;
>>>> +				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
>>>> +				COPY_PHASE_STRIP = YES;
>>>> +				CURRENT_PROJECT_VERSION = 360.99.0;
>>>> +				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
>>>> +				ENABLE_NS_ASSERTIONS = NO;
>>>> +				GCC_C_LANGUAGE_STANDARD = gnu99;
>>>> +				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
>>>> +				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
>>>> +				INSTALL_PATH = "$(LLDB_TOOLS_INSTALL_DIR)";
>>>> +				MTL_ENABLE_DEBUG_INFO = NO;
>>>> +				"OTHER_LDFLAGS[sdk=iphoneos*]" = (
>>>> +					"-sectcreate",
>>>> +					__TEXT,
>>>> +					__info_plist,
>>>> +					"$(PROJECT_DIR)/tools/lldb-vscode/lldb-vscode-Info.plist",
>>>> +					"-Wl,-rpath, at loader_path/../../../System/Library/PrivateFrameworks",
>>>> +					"-filelist",
>>>> +					"$(LLVM_BUILD_DIR)/archives.txt",
>>>> +				);
>>>> +				"OTHER_LDFLAGS[sdk=macosx*]" = (
>>>> +					"-sectcreate",
>>>> +					__TEXT,
>>>> +					__info_plist,
>>>> +					"$(PROJECT_DIR)/tools/lldb-vscode/lldb-vscode-Info.plist",
>>>> +					"-Wl,-rpath, at loader_path/../../Library/PrivateFrameworks/",
>>>> +					"-Wl,-rpath, at loader_path/../../../SharedFrameworks",
>>>> +					"-Wl,-rpath, at loader_path/../../System/Library/PrivateFrameworks",
>>>> +					"-Wl,-rpath, at loader_path/../../Library/PrivateFrameworks",
>>>> +					"-filelist",
>>>> +					"$(LLVM_BUILD_DIR)/archives.txt",
>>>> +				);
>>>> +				PRODUCT_NAME = "$(TARGET_NAME)";
>>>> +				SDKROOT = macosx;
>>>> +				STRIP_INSTALLED_PRODUCT = YES;
>>>> +				USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source $(LLVM_SOURCE_DIR)/include $(LLVM_SOURCE_DIR)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/tools/clang/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/lib/Target/ARM";
>>>> +				VERSIONING_SYSTEM = "apple-generic";
>>>> +			};
>>>> +			name = BuildAndIntegration;
>>>> +		};
>>>> 		2687EAC71508110B00DD8C2E /* Debug */ = {
>>>> 			isa = XCBuildConfiguration;
>>>> 			buildSettings = {
>>>> @@ -10965,6 +11300,17 @@
>>>> 			);
>>>> 			defaultConfigurationIsVisible = 0;
>>>> 			defaultConfigurationName = BuildAndIntegration;
>>>> +		};
>>>> +		26792614211CA3AD00EE1D10 /* Build configuration list for PBXNativeTarget "lldb-vscode" */ = {
>>>> +			isa = XCConfigurationList;
>>>> +			buildConfigurations = (
>>>> +				26792610211CA3AD00EE1D10 /* Debug */,
>>>> +				26792611211CA3AD00EE1D10 /* DebugClang */,
>>>> +				26792612211CA3AD00EE1D10 /* Release */,
>>>> +				26792613211CA3AD00EE1D10 /* BuildAndIntegration */,
>>>> +			);
>>>> +			defaultConfigurationIsVisible = 0;
>>>> +			defaultConfigurationName = BuildAndIntegration;
>>>> 		};
>>>> 		2687EAC61508110B00DD8C2E /* Build configuration list for PBXLegacyTarget "install-headers" */ = {
>>>> 			isa = XCConfigurationList;
>>>> 
>>>> Modified: lldb/trunk/packages/Python/lldbsuite/test/dotest.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/dotest.py?rev=339911&r1=339910&r2=339911&view=diff <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/dotest.py?rev=339911&r1=339910&r2=339911&view=diff>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/dotest.py (original)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/dotest.py Thu Aug 16 10:59:38 2018
>>>> @@ -646,6 +646,7 @@ def setupSysPath():
>>>> 
>>>>     pluginPath = os.path.join(scriptPath, 'plugins')
>>>>     toolsLLDBMIPath = os.path.join(scriptPath, 'tools', 'lldb-mi')
>>>> +    toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
>>>>     toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
>>>> 
>>>>     # Insert script dir, plugin dir, lldb-mi dir and lldb-server dir to the
>>>> @@ -654,6 +655,9 @@ def setupSysPath():
>>>>     # Adding test/tools/lldb-mi to the path makes it easy
>>>>     sys.path.insert(0, toolsLLDBMIPath)
>>>>     # to "import lldbmi_testcase" from the MI tests
>>>> +    # Adding test/tools/lldb-vscode to the path makes it easy to
>>>> +    # "import lldb_vscode_testcase" from the VSCode tests
>>>> +    sys.path.insert(0, toolsLLDBVSCode)
>>>>     # Adding test/tools/lldb-server to the path makes it easy
>>>>     sys.path.insert(0, toolsLLDBServerPath)
>>>>     # to "import lldbgdbserverutils" from the lldb-server tests
>>>> @@ -723,6 +727,15 @@ def setupSysPath():
>>>>                 "The 'lldb-mi' executable cannot be located.  The lldb-mi tests can not be run as a result.")
>>>>             configuration.skipCategories.append("lldb-mi")
>>>> 
>>>> +    lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode")
>>>> +    if is_exe(lldbVSCodeExec):
>>>> +        os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec
>>>> +    else:
>>>> +        if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]):
>>>> +            print(
>>>> +                "The 'lldb-vscode' executable cannot be located.  The lldb-vscode tests can not be run as a result.")
>>>> +            configuration.skipCategories.append("lldb-vscode")
>>>> +
>>>>     lldbPythonDir = None  # The directory that contains 'lldb/__init__.py'
>>>>     if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")):
>>>>         configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework")
>>>> 
>>>> Modified: lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py?rev=339911&r1=339910&r2=339911&view=diff <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py?rev=339911&r1=339910&r2=339911&view=diff>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py (original)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py Thu Aug 16 10:59:38 2018
>>>> @@ -740,6 +740,11 @@ class Base(unittest2.TestCase):
>>>>         else:
>>>>             self.lldbMiExec = None
>>>> 
>>>> +        if "LLDBVSCODE_EXEC" in os.environ:
>>>> +            self.lldbVSCodeExec = os.environ["LLDBVSCODE_EXEC"]
>>>> +        else:
>>>> +            self.lldbVSCodeExec = None
>>>> +
>>>>         # If we spawn an lldb process for test (via pexpect), do not load the
>>>>         # init file unless told otherwise.
>>>>         if "NO_LLDBINIT" in os.environ and "NO" == os.environ["NO_LLDBINIT"]:
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/.categories
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/.categories?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/.categories?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/.categories (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/.categories Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1 @@
>>>> +lldb-vscode
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/Makefile
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/Makefile?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/Makefile?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/Makefile (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/Makefile Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,5 @@
>>>> +LEVEL = ../../../make
>>>> +
>>>> +C_SOURCES := main.c
>>>> +
>>>> +include $(LEVEL)/Makefile.rules
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/TestVSCode_attach.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,176 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import shutil
>>>> +import subprocess
>>>> +import tempfile
>>>> +import threading
>>>> +import time
>>>> +
>>>> +
>>>> +def spawn_and_wait(program, delay):
>>>> +    if delay:
>>>> +        time.sleep(delay)
>>>> +    process = subprocess.Popen([program],
>>>> +                               stdin=subprocess.PIPE,
>>>> +                               stdout=subprocess.PIPE,
>>>> +                               stderr=subprocess.PIPE)
>>>> +    process.wait()
>>>> +
>>>> +
>>>> +class TestVSCode_attach(lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    def set_and_hit_breakpoint(self, continueToExit=True):
>>>> +        source = 'main.c'
>>>> +        breakpoint1_line = line_number(source, '// breakpoint 1')
>>>> +        lines = [breakpoint1_line]
>>>> +        # Set breakoint in the thread function so we can step the threads
>>>> +        breakpoint_ids = self.set_source_breakpoints(source, lines)
>>>> +        self.assertTrue(len(breakpoint_ids) == len(lines),
>>>> +                        "expect correct number of breakpoints")
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        if continueToExit:
>>>> +            self.continue_to_exit()
>>>> +
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_by_pid(self):
>>>> +        '''
>>>> +            Tests attaching to a process by process ID.
>>>> +        '''
>>>> +        self.build_and_create_debug_adaptor()
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.process = subprocess.Popen([program],
>>>> +                                        stdin=subprocess.PIPE,
>>>> +                                        stdout=subprocess.PIPE,
>>>> +                                        stderr=subprocess.PIPE)
>>>> +        self.attach(pid=self.process.pid)
>>>> +        self.set_and_hit_breakpoint(continueToExit=True)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_by_name(self):
>>>> +        '''
>>>> +            Tests attaching to a process by process name.
>>>> +        '''
>>>> +        self.build_and_create_debug_adaptor()
>>>> +        orig_program = self.getBuildArtifact("a.out")
>>>> +        # Since we are going to attach by process name, we need a unique
>>>> +        # process name that has minimal chance to match a process that is
>>>> +        # already running. To do this we use tempfile.mktemp() to give us a
>>>> +        # full path to a location where we can copy our executable. We then
>>>> +        # run this copy to ensure we don't get the error "more that one
>>>> +        # process matches 'a.out'".
>>>> +        program = tempfile.mktemp()
>>>> +        shutil.copyfile(orig_program, program)
>>>> +        shutil.copymode(orig_program, program)
>>>> +        self.process = subprocess.Popen([program],
>>>> +                                        stdin=subprocess.PIPE,
>>>> +                                        stdout=subprocess.PIPE,
>>>> +                                        stderr=subprocess.PIPE)
>>>> +        # Wait for a bit to ensure the process is launched
>>>> +        time.sleep(1)
>>>> +        self.attach(program=program)
>>>> +        self.set_and_hit_breakpoint(continueToExit=True)
>>>> +
>>>> +    @skipUnlessDarwin
>>>> +    @no_debug_info_test
>>>> +    def test_by_name_waitFor(self):
>>>> +        '''
>>>> +            Tests attaching to a process by process name and waiting for the
>>>> +            next instance of a process to be launched, ingoring all current
>>>> +            ones.
>>>> +        '''
>>>> +        self.build_and_create_debug_adaptor()
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.spawn_thread = threading.Thread(target=spawn_and_wait,
>>>> +                                             args=(program, 1.0,))
>>>> +        self.spawn_thread.start()
>>>> +        self.attach(program=program, waitFor=True)
>>>> +        self.set_and_hit_breakpoint(continueToExit=True)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_commands(self):
>>>> +        '''
>>>> +            Tests the "initCommands", "preRunCommands", "stopCommands",
>>>> +            "exitCommands", and "attachCommands" that can be passed during
>>>> +            attach.
>>>> +
>>>> +            "initCommands" are a list of LLDB commands that get executed
>>>> +            before the targt is created.
>>>> +            "preRunCommands" are a list of LLDB commands that get executed
>>>> +            after the target has been created and before the launch.
>>>> +            "stopCommands" are a list of LLDB commands that get executed each
>>>> +            time the program stops.
>>>> +            "exitCommands" are a list of LLDB commands that get executed when
>>>> +            the process exits
>>>> +            "attachCommands" are a list of LLDB commands that get executed and
>>>> +            must have a valid process in the selected target in LLDB after
>>>> +            they are done executing. This allows custom commands to create any
>>>> +            kind of debug session.
>>>> +        '''
>>>> +        self.build_and_create_debug_adaptor()
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        # Here we just create a target and launch the process as a way to test
>>>> +        # if we are able to use attach commands to create any kind of a target
>>>> +        # and use it for debugging
>>>> +        attachCommands = [
>>>> +            'target create -d "%s"' % (program),
>>>> +            'process launch -- arg1'
>>>> +        ]
>>>> +        initCommands = ['target list', 'platform list']
>>>> +        preRunCommands = ['image list a.out', 'image dump sections a.out']
>>>> +        stopCommands = ['frame variable', 'bt']
>>>> +        exitCommands = ['expr 2+3', 'expr 3+4']
>>>> +        self.attach(program=program,
>>>> +                    attachCommands=attachCommands,
>>>> +                    initCommands=initCommands,
>>>> +                    preRunCommands=preRunCommands,
>>>> +                    stopCommands=stopCommands,
>>>> +                    exitCommands=exitCommands)
>>>> +
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "initCommands" and the "preRunCommands".
>>>> +        output = self.get_console()
>>>> +        # Verify all "initCommands" were found in console output
>>>> +        self.verify_commands('initCommands', output, initCommands)
>>>> +        # Verify all "preRunCommands" were found in console output
>>>> +        self.verify_commands('preRunCommands', output, preRunCommands)
>>>> +
>>>> +        functions = ['main']
>>>> +        breakpoint_ids = self.set_function_breakpoints(functions)
>>>> +        self.assertTrue(len(breakpoint_ids) == len(functions),
>>>> +                        "expect one breakpoint")
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        output = self.get_console(timeout=1.0)
>>>> +        self.verify_commands('stopCommands', output, stopCommands)
>>>> +
>>>> +        # Continue after launch and hit the "pause()" call and stop the target.
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "stopCommands" that were run after we stop.
>>>> +        self.vscode.request_continue()
>>>> +        time.sleep(0.5)
>>>> +        self.vscode.request_pause()
>>>> +        self.vscode.wait_for_stopped()
>>>> +        output = self.get_console(timeout=1.0)
>>>> +        self.verify_commands('stopCommands', output, stopCommands)
>>>> +
>>>> +        # Continue until the program exits
>>>> +        self.continue_to_exit()
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "exitCommands" that were run after the second breakpoint was hit
>>>> +        output = self.get_console(timeout=1.0)
>>>> +        self.verify_commands('exitCommands', output, exitCommands)
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/main.c
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/main.c?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/main.c?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/main.c (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/attach/main.c Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,8 @@
>>>> +#include <stdio.h>
>>>> +#include <unistd.h>
>>>> +
>>>> +int main(int argc, char const *argv[]) {
>>>> +  printf("pid = %i\n", getpid());
>>>> +  sleep(5);
>>>> +  return 0; // breakpoint 1
>>>> +}
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/Makefile
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/Makefile?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/Makefile?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/Makefile (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/Makefile Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,5 @@
>>>> +LEVEL = ../../../make
>>>> +
>>>> +CXX_SOURCES := main.cpp
>>>> +
>>>> +include $(LEVEL)/Makefile.rules
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setBreakpoints.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,209 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import pprint
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +
>>>> +
>>>> +class TestVSCode_setBreakpoints(lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_set_and_clear(self):
>>>> +        '''Tests setting and clearing source file and line breakpoints.
>>>> +           This packet is a bit tricky on the debug adaptor side since there
>>>> +           is no "clearBreakpoints" packet. Source file and line breakpoints
>>>> +           are set by sending a "setBreakpoints" packet with a source file
>>>> +           specified and zero or more source lines. If breakpoints have been
>>>> +           set in the source file before, any exising breakpoints must remain
>>>> +           set, and any new breakpoints must be created, and any breakpoints
>>>> +           that were in previous requests and are not in the current request
>>>> +           must be removed. This function tests this setting and clearing
>>>> +           and makes sure things happen correctly. It doesn't test hitting
>>>> +           breakpoints and the functionality of each breakpoint, like
>>>> +           'conditions' and 'hitCondition' settings.'''
>>>> +        source_basename = 'main.cpp'
>>>> +        source_path = os.path.join(os.getcwd(), source_basename)
>>>> +        first_line = line_number('main.cpp', 'break 12')
>>>> +        second_line = line_number('main.cpp', 'break 13')
>>>> +        third_line = line_number('main.cpp', 'break 14')
>>>> +        lines = [first_line, second_line, third_line]
>>>> +
>>>> +        # Visual Studio Code Debug Adaptors have no way to specify the file
>>>> +        # without launching or attaching to a process, so we must start a
>>>> +        # process in order to be able to set breakpoints.
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +
>>>> +        # Set 3 breakoints and verify that they got set correctly
>>>> +        response = self.vscode.request_setBreakpoints(source_path, lines)
>>>> +        line_to_id = {}
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +            for breakpoint in breakpoints:
>>>> +                line = breakpoint['line']
>>>> +                # Store the "id" of the breakpoint that was set for later
>>>> +                line_to_id[line] = breakpoint['id']
>>>> +                self.assertTrue(line in lines, "line expected in lines array")
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint verified")
>>>> +
>>>> +        # There is no breakpoint delete packet, clients just send another
>>>> +        # setBreakpoints packet with the same source file with fewer lines.
>>>> +        # Below we remove the second line entry and call the setBreakpoints
>>>> +        # function again. We want to verify that any breakpoints that were set
>>>> +        # before still have the same "id". This means we didn't clear the
>>>> +        # breakpoint and set it again at the same location. We also need to
>>>> +        # verify that the second line location was actually removed.
>>>> +        lines.remove(second_line)
>>>> +        # Set 2 breakoints and verify that the previous breakoints that were
>>>> +        # set above are still set.
>>>> +        response = self.vscode.request_setBreakpoints(source_path, lines)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +            for breakpoint in breakpoints:
>>>> +                line = breakpoint['line']
>>>> +                # Verify the same breakpoints are still set within LLDB by
>>>> +                # making sure the breakpoint ID didn't change
>>>> +                self.assertTrue(line_to_id[line] == breakpoint['id'],
>>>> +                                "verify previous breakpoints stayed the same")
>>>> +                self.assertTrue(line in lines, "line expected in lines array")
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint still verified")
>>>> +
>>>> +        # Now get the full list of breakpoints set in the target and verify
>>>> +        # we have only 2 breakpoints set. The response above could have told
>>>> +        # us about 2 breakpoints, but we want to make sure we don't have the
>>>> +        # third one still set in the target
>>>> +        response = self.vscode.request_testGetTargetBreakpoints()
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +            for breakpoint in breakpoints:
>>>> +                line = breakpoint['line']
>>>> +                # Verify the same breakpoints are still set within LLDB by
>>>> +                # making sure the breakpoint ID didn't change
>>>> +                self.assertTrue(line_to_id[line] == breakpoint['id'],
>>>> +                                "verify previous breakpoints stayed the same")
>>>> +                self.assertTrue(line in lines, "line expected in lines array")
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint still verified")
>>>> +
>>>> +        # Now clear all breakpoints for the source file by passing down an
>>>> +        # empty lines array
>>>> +        lines = []
>>>> +        response = self.vscode.request_setBreakpoints(source_path, lines)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +
>>>> +        # Verify with the target that all breakpoints have been cleared
>>>> +        response = self.vscode.request_testGetTargetBreakpoints()
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +
>>>> +        # Now set a breakpoint again in the same source file and verify it
>>>> +        # was added.
>>>> +        lines = [second_line]
>>>> +        response = self.vscode.request_setBreakpoints(source_path, lines)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +            for breakpoint in breakpoints:
>>>> +                line = breakpoint['line']
>>>> +                self.assertTrue(line in lines, "line expected in lines array")
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint still verified")
>>>> +
>>>> +        # Now get the full list of breakpoints set in the target and verify
>>>> +        # we have only 2 breakpoints set. The response above could have told
>>>> +        # us about 2 breakpoints, but we want to make sure we don't have the
>>>> +        # third one still set in the target
>>>> +        response = self.vscode.request_testGetTargetBreakpoints()
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(lines),
>>>> +                            "expect %u source breakpoints" % (len(lines)))
>>>> +            for breakpoint in breakpoints:
>>>> +                line = breakpoint['line']
>>>> +                self.assertTrue(line in lines, "line expected in lines array")
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint still verified")
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_functionality(self):
>>>> +        '''Tests hitting breakpoints and the functionality of a single
>>>> +           breakpoint, like 'conditions' and 'hitCondition' settings.'''
>>>> +        source_basename = 'main.cpp'
>>>> +        source_path = os.path.join(os.getcwd(), source_basename)
>>>> +        loop_line = line_number('main.cpp', '// break loop')
>>>> +
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        # Set a breakpoint at the loop line with no condition and no
>>>> +        # hitCondition
>>>> +        breakpoint_ids = self.set_source_breakpoints(source_path, [loop_line])
>>>> +        self.assertTrue(len(breakpoint_ids) == 1, "expect one breakpoint")
>>>> +        self.vscode.request_continue()
>>>> +
>>>> +        # Verify we hit the breakpoint we just set
>>>> +        self.verify_breakpoint_hit(breakpoint_ids)
>>>> +
>>>> +        # Make sure i is zero at first breakpoint
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 0, 'i != 0 after hitting breakpoint')
>>>> +
>>>> +        # Update the condition on our breakpoint
>>>> +        new_breakpoint_ids = self.set_source_breakpoints(source_path,
>>>> +                                                         [loop_line],
>>>> +                                                         condition="i==4")
>>>> +        self.assertTrue(breakpoint_ids == new_breakpoint_ids,
>>>> +                        "existing breakpoint should have its condition "
>>>> +                        "updated")
>>>> +
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 4,
>>>> +                        'i != 4 showing conditional works')
>>>> +
>>>> +        new_breakpoint_ids = self.set_source_breakpoints(source_path,
>>>> +                                                         [loop_line],
>>>> +                                                         hitCondition="2")
>>>> +
>>>> +        self.assertTrue(breakpoint_ids == new_breakpoint_ids,
>>>> +                        "existing breakpoint should have its condition "
>>>> +                        "updated")
>>>> +
>>>> +        # Continue with a hitContidtion of 2 and expect it to skip 1 value
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 6,
>>>> +                        'i != 6 showing hitCondition works')
>>>> +
>>>> +        # continue after hitting our hitCondition and make sure it only goes
>>>> +        # up by 1
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 7,
>>>> +                        'i != 7 showing post hitCondition hits every time')
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setExceptionBreakpoints.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setExceptionBreakpoints.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setExceptionBreakpoints.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setExceptionBreakpoints.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setExceptionBreakpoints.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,50 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import pprint
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +
>>>> +
>>>> +class TestVSCode_setExceptionBreakpoints(
>>>> +        lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_functionality(self):
>>>> +        '''Tests setting and clearing exception breakpoints.
>>>> +           This packet is a bit tricky on the debug adaptor side since there
>>>> +           is no "clear exception breakpoints" packet. Exception breakpoints
>>>> +           are set by sending a "setExceptionBreakpoints" packet with zero or
>>>> +           more exception filters. If exception breakpoints have been set
>>>> +           before, any exising breakpoints must remain set, and any new
>>>> +           breakpoints must be created, and any breakpoints that were in
>>>> +           previous requests and are not in the current request must be
>>>> +           removed. This exception tests this setting and clearing and makes
>>>> +           sure things happen correctly. It doesn't test hitting breakpoints
>>>> +           and the functionality of each breakpoint, like 'conditions' and
>>>> +           x'hitCondition' settings.
>>>> +        '''
>>>> +        # Visual Studio Code Debug Adaptors have no way to specify the file
>>>> +        # without launching or attaching to a process, so we must start a
>>>> +        # process in order to be able to set breakpoints.
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +
>>>> +        filters = ['cpp_throw', 'cpp_catch']
>>>> +        response = self.vscode.request_setExceptionBreakpoints(filters)
>>>> +        if response:
>>>> +            self.assertTrue(response['success'])
>>>> +
>>>> +        self.continue_to_exception_breakpoint('C++ Throw')
>>>> +        self.continue_to_exception_breakpoint('C++ Catch')
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setFunctionBreakpoints.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setFunctionBreakpoints.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setFunctionBreakpoints.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setFunctionBreakpoints.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/TestVSCode_setFunctionBreakpoints.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,164 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import pprint
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +
>>>> +
>>>> +class TestVSCode_setFunctionBreakpoints(
>>>> +        lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_set_and_clear(self):
>>>> +        '''Tests setting and clearing function breakpoints.
>>>> +           This packet is a bit tricky on the debug adaptor side since there
>>>> +           is no "clearFunction Breakpoints" packet. Function breakpoints
>>>> +           are set by sending a "setFunctionBreakpoints" packet with zero or
>>>> +           more function names. If function breakpoints have been set before,
>>>> +           any exising breakpoints must remain set, and any new breakpoints
>>>> +           must be created, and any breakpoints that were in previous requests
>>>> +           and are not in the current request must be removed. This function
>>>> +           tests this setting and clearing and makes sure things happen
>>>> +           correctly. It doesn't test hitting breakpoints and the functionality
>>>> +           of each breakpoint, like 'conditions' and 'hitCondition' settings.
>>>> +        '''
>>>> +        # Visual Studio Code Debug Adaptors have no way to specify the file
>>>> +        # without launching or attaching to a process, so we must start a
>>>> +        # process in order to be able to set breakpoints.
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        bp_id_12 = None
>>>> +        functions = ['twelve']
>>>> +        # Set a function breakpoint at 'twelve'
>>>> +        response = self.vscode.request_setFunctionBreakpoints(functions)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(functions),
>>>> +                            "expect %u source breakpoints" % (len(functions)))
>>>> +            for breakpoint in breakpoints:
>>>> +                bp_id_12 = breakpoint['id']
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint verified")
>>>> +
>>>> +        # Add an extra name and make sure we have two breakpoints after this
>>>> +        functions.append('thirteen')
>>>> +        response = self.vscode.request_setFunctionBreakpoints(functions)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(functions),
>>>> +                            "expect %u source breakpoints" % (len(functions)))
>>>> +            for breakpoint in breakpoints:
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint verified")
>>>> +
>>>> +        # There is no breakpoint delete packet, clients just send another
>>>> +        # setFunctionBreakpoints packet with the different function names.
>>>> +        functions.remove('thirteen')
>>>> +        response = self.vscode.request_setFunctionBreakpoints(functions)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(functions),
>>>> +                            "expect %u source breakpoints" % (len(functions)))
>>>> +            for breakpoint in breakpoints:
>>>> +                bp_id = breakpoint['id']
>>>> +                self.assertTrue(bp_id == bp_id_12,
>>>> +                                'verify "twelve" breakpoint ID is same')
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint still verified")
>>>> +
>>>> +        # Now get the full list of breakpoints set in the target and verify
>>>> +        # we have only 1 breakpoints set. The response above could have told
>>>> +        # us about 1 breakpoints, but we want to make sure we don't have the
>>>> +        # second one still set in the target
>>>> +        response = self.vscode.request_testGetTargetBreakpoints()
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(functions),
>>>> +                            "expect %u source breakpoints" % (len(functions)))
>>>> +            for breakpoint in breakpoints:
>>>> +                bp_id = breakpoint['id']
>>>> +                self.assertTrue(bp_id == bp_id_12,
>>>> +                                'verify "twelve" breakpoint ID is same')
>>>> +                self.assertTrue(breakpoint['verified'],
>>>> +                                "expect breakpoint still verified")
>>>> +
>>>> +        # Now clear all breakpoints for the source file by passing down an
>>>> +        # empty lines array
>>>> +        functions = []
>>>> +        response = self.vscode.request_setFunctionBreakpoints(functions)
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(functions),
>>>> +                            "expect %u source breakpoints" % (len(functions)))
>>>> +
>>>> +        # Verify with the target that all breakpoints have been cleared
>>>> +        response = self.vscode.request_testGetTargetBreakpoints()
>>>> +        if response:
>>>> +            breakpoints = response['body']['breakpoints']
>>>> +            self.assertTrue(len(breakpoints) == len(functions),
>>>> +                            "expect %u source breakpoints" % (len(functions)))
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_functionality(self):
>>>> +        '''Tests hitting breakpoints and the functionality of a single
>>>> +           breakpoint, like 'conditions' and 'hitCondition' settings.'''
>>>> +
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        # Set a breakpoint on "twelve" with no condition and no hitCondition
>>>> +        functions = ['twelve']
>>>> +        breakpoint_ids = self.set_function_breakpoints(functions)
>>>> +
>>>> +        self.assertTrue(len(breakpoint_ids) == len(functions),
>>>> +                        "expect one breakpoint")
>>>> +
>>>> +        # Verify we hit the breakpoint we just set
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +
>>>> +        # Make sure i is zero at first breakpoint
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 0, 'i != 0 after hitting breakpoint')
>>>> +
>>>> +        # Update the condition on our breakpoint
>>>> +        new_breakpoint_ids = self.set_function_breakpoints(functions,
>>>> +                                                           condition="i==4")
>>>> +        self.assertTrue(breakpoint_ids == new_breakpoint_ids,
>>>> +                        "existing breakpoint should have its condition "
>>>> +                        "updated")
>>>> +
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 4,
>>>> +                        'i != 4 showing conditional works')
>>>> +        new_breakpoint_ids = self.set_function_breakpoints(functions,
>>>> +                                                           hitCondition="2")
>>>> +
>>>> +        self.assertTrue(breakpoint_ids == new_breakpoint_ids,
>>>> +                        "existing breakpoint should have its condition "
>>>> +                        "updated")
>>>> +
>>>> +        # Continue with a hitContidtion of 2 and expect it to skip 1 value
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 6,
>>>> +                        'i != 6 showing hitCondition works')
>>>> +
>>>> +        # continue after hitting our hitCondition and make sure it only goes
>>>> +        # up by 1
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        i = int(self.vscode.get_local_variable_value('i'))
>>>> +        self.assertTrue(i == 7,
>>>> +                        'i != 7 showing post hitCondition hits every time')
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/main.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/main.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/main.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/main.cpp (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/breakpoint/main.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,27 @@
>>>> +#include <stdio.h>
>>>> +#include <stdexcept>
>>>> +
>>>> +int twelve(int i) {
>>>> +  return 12 + i; // break 12
>>>> +}
>>>> +
>>>> +int thirteen(int i) {
>>>> +  return 13 + i; // break 13
>>>> +}
>>>> +
>>>> +namespace a {
>>>> +  int fourteen(int i) {
>>>> +    return 14 + i; // break 14
>>>> +  }
>>>> +}
>>>> +int main(int argc, char const *argv[]) {
>>>> +  for (int i=0; i<10; ++i) {
>>>> +    int x = twelve(i) + thirteen(i) + a::fourteen(i); // break loop
>>>> +  }
>>>> +  try {
>>>> +    throw std::invalid_argument( "throwing exception for testing" );
>>>> +  } catch (...) {
>>>> +    puts("caught exception...");
>>>> +  }
>>>> +  return 0;
>>>> +}
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/Makefile
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/Makefile?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/Makefile?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/Makefile (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/Makefile Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,5 @@
>>>> +LEVEL = ../../../make
>>>> +
>>>> +C_SOURCES := main.c
>>>> +
>>>> +include $(LEVEL)/Makefile.rules
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/TestVSCode_launch.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/TestVSCode_launch.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/TestVSCode_launch.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/TestVSCode_launch.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/TestVSCode_launch.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,331 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import pprint
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +import time
>>>> +
>>>> +
>>>> +class TestVSCode_launch(lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_default(self):
>>>> +        '''
>>>> +            Tests the default launch of a simple program. No arguments,
>>>> +            environment, or anything else is specified.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        self.continue_to_exit()
>>>> +        # Now get the STDOUT and verify our program argument is correct
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect program output")
>>>> +        lines = output.splitlines()
>>>> +        self.assertTrue(program in lines[0],
>>>> +                        "make sure program path is in first argument")
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_stopOnEntry(self):
>>>> +        '''
>>>> +            Tests the default launch of a simple program that stops at the
>>>> +            entry point instead of continuing.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program, stopOnEntry=True)
>>>> +        self.set_function_breakpoints(['main'])
>>>> +        stopped_events = self.continue_to_next_stop()
>>>> +        for stopped_event in stopped_events:
>>>> +            if 'body' in stopped_event:
>>>> +                body = stopped_event['body']
>>>> +                if 'reason' in body:
>>>> +                    reason = body['reason']
>>>> +                    self.assertTrue(
>>>> +                        reason != 'breakpoint',
>>>> +                        'verify stop isn\'t "main" breakpoint')
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_cwd(self):
>>>> +        '''
>>>> +            Tests the default launch of a simple program with a current working
>>>> +            directory.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        program_parent_dir = os.path.split(os.path.split(program)[0])[0]
>>>> +        self.build_and_launch(program,
>>>> +                              cwd=program_parent_dir)
>>>> +        self.continue_to_exit()
>>>> +        # Now get the STDOUT and verify our program argument is correct
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect program output")
>>>> +        lines = output.splitlines()
>>>> +        found = False
>>>> +        for line in lines:
>>>> +            if line.startswith('cwd = \"'):
>>>> +                quote_path = '"%s"' % (program_parent_dir)
>>>> +                found = True
>>>> +                self.assertTrue(quote_path in line,
>>>> +                                "working directory '%s' not in '%s'" % (
>>>> +                                    program_parent_dir, line))
>>>> +        self.assertTrue(found, "verified program working directory")
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_debuggerRoot(self):
>>>> +        '''
>>>> +            Tests the "debuggerRoot" will change the working directory of
>>>> +            the lldb-vscode debug adaptor.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        program_parent_dir = os.path.split(os.path.split(program)[0])[0]
>>>> +        commands = ['platform shell echo cwd = $PWD']
>>>> +        self.build_and_launch(program,
>>>> +                              debuggerRoot=program_parent_dir,
>>>> +                              initCommands=commands)
>>>> +        output = self.get_console()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect console output")
>>>> +        lines = output.splitlines()
>>>> +        prefix = 'cwd = '
>>>> +        found = False
>>>> +        for line in lines:
>>>> +            if line.startswith(prefix):
>>>> +                found = True
>>>> +                self.assertTrue(program_parent_dir == line[len(prefix):],
>>>> +                                "lldb-vscode working dir '%s' == '%s'" % (
>>>> +                                    program_parent_dir, line[6:]))
>>>> +        self.assertTrue(found, "verified lldb-vscode working directory")
>>>> +        self.continue_to_exit()
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_sourcePath(self):
>>>> +        '''
>>>> +            Tests the "sourcePath" will set the target.source-map.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        program_dir = os.path.split(program)[0]
>>>> +        self.build_and_launch(program,
>>>> +                              sourcePath=program_dir)
>>>> +        output = self.get_console()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect console output")
>>>> +        lines = output.splitlines()
>>>> +        prefix = '(lldb) settings set target.source-map "." '
>>>> +        found = False
>>>> +        for line in lines:
>>>> +            if line.startswith(prefix):
>>>> +                found = True
>>>> +                quoted_path = '"%s"' % (program_dir)
>>>> +                self.assertTrue(quoted_path == line[len(prefix):],
>>>> +                                "lldb-vscode working dir %s == %s" % (
>>>> +                                    quoted_path, line[6:]))
>>>> +        self.assertTrue(found, 'found "sourcePath" in console output')
>>>> +        self.continue_to_exit()
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_disableSTDIO(self):
>>>> +        '''
>>>> +            Tests the default launch of a simple program with STDIO disabled.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program,
>>>> +                              disableSTDIO=True)
>>>> +        self.continue_to_exit()
>>>> +        # Now get the STDOUT and verify our program argument is correct
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output is None or len(output) == 0,
>>>> +                        "expect no program output")
>>>> +
>>>> +    @skipUnlessDarwin
>>>> +    @skipIfDarwinEmbedded
>>>> +    @no_debug_info_test
>>>> +    def test_shellExpandArguments_enabled(self):
>>>> +        '''
>>>> +            Tests the default launch of a simple program with shell expansion
>>>> +            enabled.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        program_dir = os.path.split(program)[0]
>>>> +        glob = os.path.join(program_dir, '*.out')
>>>> +        self.build_and_launch(program, args=[glob], shellExpandArguments=True)
>>>> +        self.continue_to_exit()
>>>> +        # Now get the STDOUT and verify our program argument is correct
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect no program output")
>>>> +        lines = output.splitlines()
>>>> +        for line in lines:
>>>> +            quote_path = '"%s"' % (program)
>>>> +            if line.startswith("arg[1] ="):
>>>> +                self.assertTrue(quote_path in line,
>>>> +                                'verify "%s" expanded to "%s"' % (
>>>> +                                    glob, program))
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_shellExpandArguments_disabled(self):
>>>> +        '''
>>>> +            Tests the default launch of a simple program with shell expansion
>>>> +            disabled.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        program_dir = os.path.split(program)[0]
>>>> +        glob = os.path.join(program_dir, '*.out')
>>>> +        self.build_and_launch(program,
>>>> +                              args=[glob],
>>>> +                              shellExpandArguments=False)
>>>> +        self.continue_to_exit()
>>>> +        # Now get the STDOUT and verify our program argument is correct
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect no program output")
>>>> +        lines = output.splitlines()
>>>> +        for line in lines:
>>>> +            quote_path = '"%s"' % (glob)
>>>> +            if line.startswith("arg[1] ="):
>>>> +                self.assertTrue(quote_path in line,
>>>> +                                'verify "%s" stayed to "%s"' % (
>>>> +                                    glob, glob))
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_args(self):
>>>> +        '''
>>>> +            Tests launch of a simple program with arguments
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        args = ["one", "with space", "'with single quotes'",
>>>> +                '"with double quotes"']
>>>> +        self.build_and_launch(program,
>>>> +                              args=args)
>>>> +        self.continue_to_exit()
>>>> +
>>>> +        # Now get the STDOUT and verify our arguments got passed correctly
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect program output")
>>>> +        lines = output.splitlines()
>>>> +        # Skip the first argument that contains the program name
>>>> +        lines.pop(0)
>>>> +        # Make sure arguments we specified are correct
>>>> +        for (i, arg) in enumerate(args):
>>>> +            quoted_arg = '"%s"' % (arg)
>>>> +            self.assertTrue(quoted_arg in lines[i],
>>>> +                            'arg[%i] "%s" not in "%s"' % (i+1, quoted_arg, lines[i]))
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_environment(self):
>>>> +        '''
>>>> +            Tests launch of a simple program with environment variables
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        env = ["NO_VALUE", "WITH_VALUE=BAR", "EMPTY_VALUE=",
>>>> +               "SPACE=Hello World"]
>>>> +        self.build_and_launch(program,
>>>> +                              env=env)
>>>> +        self.continue_to_exit()
>>>> +
>>>> +        # Now get the STDOUT and verify our arguments got passed correctly
>>>> +        output = self.get_stdout()
>>>> +        self.assertTrue(output and len(output) > 0,
>>>> +                        "expect program output")
>>>> +        lines = output.splitlines()
>>>> +        # Skip the all arguments so we have only environment vars left
>>>> +        while len(lines) and lines[0].startswith("arg["):
>>>> +            lines.pop(0)
>>>> +        # Make sure each environment variable in "env" is actually set in the
>>>> +        # program environment that was printed to STDOUT
>>>> +        for var in env:
>>>> +            found = False
>>>> +            for program_var in lines:
>>>> +                if var in program_var:
>>>> +                    found = True
>>>> +                    break
>>>> +            self.assertTrue(found,
>>>> +                            '"%s" must exist in program environment (%s)' % (
>>>> +                                var, lines))
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_commands(self):
>>>> +        '''
>>>> +            Tests the "initCommands", "preRunCommands", "stopCommands" and
>>>> +            "exitCommands" that can be passed during launch.
>>>> +
>>>> +            "initCommands" are a list of LLDB commands that get executed
>>>> +            before the targt is created.
>>>> +            "preRunCommands" are a list of LLDB commands that get executed
>>>> +            after the target has been created and before the launch.
>>>> +            "stopCommands" are a list of LLDB commands that get executed each
>>>> +            time the program stops.
>>>> +            "exitCommands" are a list of LLDB commands that get executed when
>>>> +            the process exits
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        initCommands = ['target list', 'platform list']
>>>> +        preRunCommands = ['image list a.out', 'image dump sections a.out']
>>>> +        stopCommands = ['frame variable', 'bt']
>>>> +        exitCommands = ['expr 2+3', 'expr 3+4']
>>>> +        self.build_and_launch(program,
>>>> +                              initCommands=initCommands,
>>>> +                              preRunCommands=preRunCommands,
>>>> +                              stopCommands=stopCommands,
>>>> +                              exitCommands=exitCommands)
>>>> +
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "initCommands" and the "preRunCommands".
>>>> +        output = self.get_console()
>>>> +        # Verify all "initCommands" were found in console output
>>>> +        self.verify_commands('initCommands', output, initCommands)
>>>> +        # Verify all "preRunCommands" were found in console output
>>>> +        self.verify_commands('preRunCommands', output, preRunCommands)
>>>> +
>>>> +        source = 'main.c'
>>>> +        first_line = line_number(source, '// breakpoint 1')
>>>> +        second_line = line_number(source, '// breakpoint 2')
>>>> +        lines = [first_line, second_line]
>>>> +
>>>> +        # Set 2 breakoints so we can verify that "stopCommands" get run as the
>>>> +        # breakpoints get hit
>>>> +        breakpoint_ids = self.set_source_breakpoints(source, lines)
>>>> +        self.assertTrue(len(breakpoint_ids) == len(lines),
>>>> +                        "expect correct number of breakpoints")
>>>> +
>>>> +        # Continue after launch and hit the first breakpoint.
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "stopCommands" that were run after the first breakpoint was hit
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        output = self.get_console(timeout=1.0)
>>>> +        self.verify_commands('stopCommands', output, stopCommands)
>>>> +
>>>> +        # Continue again and hit the second breakpoint.
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "stopCommands" that were run after the second breakpoint was hit
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        output = self.get_console(timeout=1.0)
>>>> +        self.verify_commands('stopCommands', output, stopCommands)
>>>> +
>>>> +        # Continue until the program exits
>>>> +        self.continue_to_exit()
>>>> +        # Get output from the console. This should contain both the
>>>> +        # "exitCommands" that were run after the second breakpoint was hit
>>>> +        output = self.get_console(timeout=1.0)
>>>> +        self.verify_commands('exitCommands', output, exitCommands)
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/main.c
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/main.c?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/main.c?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/main.c (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/launch/main.c Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,15 @@
>>>> +#include <stdio.h>
>>>> +#include <stdlib.h>
>>>> +#include <unistd.h>
>>>> +
>>>> +int main(int argc, char const *argv[], char const *envp[]) {
>>>> +  for (int i=0; i<argc; ++i)
>>>> +    printf("arg[%i] = \"%s\"\n", i, argv[i]);
>>>> +  for (int i=0; envp[i]; ++i)
>>>> +    printf("env[%i] = \"%s\"\n", i, envp[i]);
>>>> +  char *cwd = getcwd(NULL, 0);
>>>> +  printf("cwd = \"%s\"\n", cwd); // breakpoint 1
>>>> +  free(cwd);
>>>> +  cwd = NULL;
>>>> +  return 0;  // breakpoint 2
>>>> +}
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,288 @@
>>>> +from __future__ import print_function
>>>> +
>>>> +from lldbsuite.test.lldbtest import *
>>>> +import os
>>>> +import vscode
>>>> +
>>>> +
>>>> +class VSCodeTestCaseBase(TestBase):
>>>> +
>>>> +    def create_debug_adaptor(self):
>>>> +        '''Create the Visual Studio Code debug adaptor'''
>>>> +        self.assertTrue(os.path.exists(self.lldbVSCodeExec),
>>>> +                        'lldb-vscode must exist')
>>>> +        self.vscode = vscode.DebugAdaptor(executable=self.lldbVSCodeExec)
>>>> +
>>>> +    def build_and_create_debug_adaptor(self):
>>>> +        self.build()
>>>> +        self.create_debug_adaptor()
>>>> +
>>>> +    def set_source_breakpoints(self, source_path, lines, condition=None,
>>>> +                               hitCondition=None):
>>>> +        '''Sets source breakpoints and returns an array of strings containing
>>>> +           the breakpoint location IDs ("1.1", "1.2") for each breakpoint
>>>> +           that was set.
>>>> +        '''
>>>> +        response = self.vscode.request_setBreakpoints(
>>>> +            source_path, lines, condition=condition, hitCondition=hitCondition)
>>>> +        if response is None:
>>>> +            return []
>>>> +        breakpoints = response['body']['breakpoints']
>>>> +        breakpoint_ids = []
>>>> +        for breakpoint in breakpoints:
>>>> +            response_id = breakpoint['id']
>>>> +            bp_id = response_id >> 32
>>>> +            bp_loc_id = response_id & 0xffffffff
>>>> +            breakpoint_ids.append('%i.%i' % (bp_id, bp_loc_id))
>>>> +        return breakpoint_ids
>>>> +
>>>> +    def set_function_breakpoints(self, functions, condition=None,
>>>> +                                 hitCondition=None):
>>>> +        '''Sets breakpoints by function name given an array of function names
>>>> +           and returns an array of strings containing the breakpoint location
>>>> +           IDs ("1.1", "1.2") for each breakpoint that was set.
>>>> +        '''
>>>> +        response = self.vscode.request_setFunctionBreakpoints(
>>>> +            functions, condition=condition, hitCondition=hitCondition)
>>>> +        if response is None:
>>>> +            return []
>>>> +        breakpoints = response['body']['breakpoints']
>>>> +        breakpoint_ids = []
>>>> +        for breakpoint in breakpoints:
>>>> +            response_id = breakpoint['id']
>>>> +            bp_id = response_id >> 32
>>>> +            bp_loc_id = response_id & 0xffffffff
>>>> +            breakpoint_ids.append('%i.%i' % (bp_id, bp_loc_id))
>>>> +        return breakpoint_ids
>>>> +
>>>> +    def verify_breakpoint_hit(self, breakpoint_ids):
>>>> +        '''Wait for the process we are debugging to stop, and verify we hit
>>>> +           any breakpoint location in the "breakpoint_ids" array.
>>>> +           "breakpoint_ids" should be a list of breakpoint location ID strings
>>>> +           (["1.1", "2.1"]). The return value from
>>>> +           self.set_source_breakpoints() can be passed to this function'''
>>>> +        stopped_events = self.vscode.wait_for_stopped()
>>>> +        for stopped_event in stopped_events:
>>>> +            if 'body' in stopped_event:
>>>> +                body = stopped_event['body']
>>>> +                if 'reason' not in body:
>>>> +                    continue
>>>> +                if body['reason'] != 'breakpoint':
>>>> +                    continue
>>>> +                if 'description' not in body:
>>>> +                    continue
>>>> +                # Description is "breakpoint 1.1", so look for any location id
>>>> +                # ("1.1") in the description field as verification that one of
>>>> +                # the breakpoint locations was hit
>>>> +                description = body['description']
>>>> +                for breakpoint_id in breakpoint_ids:
>>>> +                    if breakpoint_id in description:
>>>> +                        return True
>>>> +        return False
>>>> +
>>>> +    def verify_exception_breakpoint_hit(self, filter_label):
>>>> +        '''Wait for the process we are debugging to stop, and verify the stop
>>>> +           reason is 'exception' and that the description matches
>>>> +           'filter_label'
>>>> +        '''
>>>> +        stopped_events = self.vscode.wait_for_stopped()
>>>> +        for stopped_event in stopped_events:
>>>> +            if 'body' in stopped_event:
>>>> +                body = stopped_event['body']
>>>> +                if 'reason' not in body:
>>>> +                    continue
>>>> +                if body['reason'] != 'exception':
>>>> +                    continue
>>>> +                if 'description' not in body:
>>>> +                    continue
>>>> +                description = body['description']
>>>> +                if filter_label == description:
>>>> +                    return True
>>>> +        return False
>>>> +
>>>> +    def verify_commands(self, flavor, output, commands):
>>>> +        self.assertTrue(output and len(output) > 0, "expect console output")
>>>> +        lines = output.splitlines()
>>>> +        prefix = '(lldb) '
>>>> +        for cmd in commands:
>>>> +            found = False
>>>> +            for line in lines:
>>>> +                if line.startswith(prefix) and cmd in line:
>>>> +                    found = True
>>>> +                    break
>>>> +            self.assertTrue(found,
>>>> +                            "verify '%s' found in console output for '%s'" % (
>>>> +                                cmd, flavor))
>>>> +
>>>> +    def get_dict_value(self, d, key_path):
>>>> +        '''Verify each key in the key_path array is in contained in each
>>>> +           dictionary within "d". Assert if any key isn't in the
>>>> +           corresponding dictionary. This is handy for grabbing values from VS
>>>> +           Code response dictionary like getting
>>>> +           response['body']['stackFrames']
>>>> +        '''
>>>> +        value = d
>>>> +        for key in key_path:
>>>> +            if key in value:
>>>> +                value = value[key]
>>>> +            else:
>>>> +                self.assertTrue(key in value,
>>>> +                                'key "%s" from key_path "%s" not in "%s"' % (
>>>> +                                    key, key_path, d))
>>>> +        return value
>>>> +
>>>> +    def get_stackFrames(self, threadId=None, startFrame=None, levels=None,
>>>> +                        dump=False):
>>>> +        response = self.vscode.request_stackTrace(threadId=threadId,
>>>> +                                                  startFrame=startFrame,
>>>> +                                                  levels=levels,
>>>> +                                                  dump=dump)
>>>> +        if response:
>>>> +            return self.get_dict_value(response, ['body', 'stackFrames'])
>>>> +        return None
>>>> +
>>>> +    def get_source_and_line(self, threadId=None, frameIndex=0):
>>>> +        stackFrames = self.get_stackFrames(threadId=threadId,
>>>> +                                           startFrame=frameIndex,
>>>> +                                           levels=1)
>>>> +        if stackFrames is not None:
>>>> +            stackFrame = stackFrames[0]
>>>> +            ['source', 'path']
>>>> +            if 'source' in stackFrame:
>>>> +                source = stackFrame['source']
>>>> +                if 'path' in source:
>>>> +                    if 'line' in stackFrame:
>>>> +                        return (source['path'], stackFrame['line'])
>>>> +        return ('', 0)
>>>> +
>>>> +    def get_stdout(self, timeout=0.0):
>>>> +        return self.vscode.get_output('stdout', timeout=timeout)
>>>> +
>>>> +    def get_console(self, timeout=0.0):
>>>> +        return self.vscode.get_output('console', timeout=timeout)
>>>> +
>>>> +    def get_local_as_int(self, name, threadId=None):
>>>> +        value = self.vscode.get_local_variable_value(name, threadId=threadId)
>>>> +        if value.startswith('0x'):
>>>> +            return int(value, 16)
>>>> +        elif value.startswith('0'):
>>>> +            return int(value, 8)
>>>> +        else:
>>>> +            return int(value)
>>>> +
>>>> +    def set_local(self, name, value, id=None):
>>>> +        '''Set a top level local variable only.'''
>>>> +        return self.vscode.request_setVariable(1, name, str(value), id=id)
>>>> +
>>>> +    def set_global(self, name, value, id=None):
>>>> +        '''Set a top level global variable only.'''
>>>> +        return self.vscode.request_setVariable(2, name, str(value), id=id)
>>>> +
>>>> +    def stepIn(self, threadId=None, waitForStop=True):
>>>> +        self.vscode.request_stepIn(threadId=threadId)
>>>> +        if waitForStop:
>>>> +            return self.vscode.wait_for_stopped()
>>>> +        return None
>>>> +
>>>> +    def stepOver(self, threadId=None, waitForStop=True):
>>>> +        self.vscode.request_next(threadId=threadId)
>>>> +        if waitForStop:
>>>> +            return self.vscode.wait_for_stopped()
>>>> +        return None
>>>> +
>>>> +    def stepOut(self, threadId=None, waitForStop=True):
>>>> +        self.vscode.request_stepOut(threadId=threadId)
>>>> +        if waitForStop:
>>>> +            return self.vscode.wait_for_stopped()
>>>> +        return None
>>>> +
>>>> +    def continue_to_next_stop(self):
>>>> +        self.vscode.request_continue()
>>>> +        return self.vscode.wait_for_stopped()
>>>> +
>>>> +    def continue_to_breakpoints(self, breakpoint_ids):
>>>> +        self.vscode.request_continue()
>>>> +        self.verify_breakpoint_hit(breakpoint_ids)
>>>> +
>>>> +    def continue_to_exception_breakpoint(self, filter_label):
>>>> +        self.vscode.request_continue()
>>>> +        self.assertTrue(self.verify_exception_breakpoint_hit(filter_label),
>>>> +                        'verify we got "%s"' % (filter_label))
>>>> +
>>>> +    def continue_to_exit(self, exitCode=0):
>>>> +        self.vscode.request_continue()
>>>> +        stopped_events = self.vscode.wait_for_stopped()
>>>> +        self.assertTrue(len(stopped_events) == 1,
>>>> +                        "expecting single 'exited' event")
>>>> +        self.assertTrue(stopped_events[0]['event'] == 'exited',
>>>> +                        'make sure program ran to completion')
>>>> +        self.assertTrue(stopped_events[0]['body']['exitCode'] == exitCode,
>>>> +                        'exitCode == %i' % (exitCode))
>>>> +
>>>> +    def attach(self, program=None, pid=None, waitFor=None, trace=None,
>>>> +               initCommands=None, preRunCommands=None, stopCommands=None,
>>>> +               exitCommands=None, attachCommands=None):
>>>> +        '''Build the default Makefile target, create the VSCode debug adaptor,
>>>> +           and attach to the process.
>>>> +        '''
>>>> +        # Make sure we disconnect and terminate the VSCode debug adaptor even
>>>> +        # if we throw an exception during the test case.
>>>> +        def cleanup():
>>>> +            self.vscode.request_disconnect(terminateDebuggee=True)
>>>> +            self.vscode.terminate()
>>>> +
>>>> +        # Execute the cleanup function during test case tear down.
>>>> +        self.addTearDownHook(cleanup)
>>>> +        # Initialize and launch the program
>>>> +        self.vscode.request_initialize()
>>>> +        response = self.vscode.request_attach(
>>>> +            program=program, pid=pid, waitFor=waitFor, trace=trace,
>>>> +            initCommands=initCommands, preRunCommands=preRunCommands,
>>>> +            stopCommands=stopCommands, exitCommands=exitCommands,
>>>> +            attachCommands=attachCommands)
>>>> +        if not (response and response['success']):
>>>> +            self.assertTrue(response['success'],
>>>> +                            'attach failed (%s)' % (response['message']))
>>>> +
>>>> +    def build_and_launch(self, program, args=None, cwd=None, env=None,
>>>> +                         stopOnEntry=False, disableASLR=True,
>>>> +                         disableSTDIO=False, shellExpandArguments=False,
>>>> +                         trace=False, initCommands=None, preRunCommands=None,
>>>> +                         stopCommands=None, exitCommands=None,
>>>> +                         sourcePath=None, debuggerRoot=None):
>>>> +        '''Build the default Makefile target, create the VSCode debug adaptor,
>>>> +           and launch the process.
>>>> +        '''
>>>> +        self.build_and_create_debug_adaptor()
>>>> +        self.assertTrue(os.path.exists(program), 'executable must exist')
>>>> +
>>>> +        # Make sure we disconnect and terminate the VSCode debug adaptor even
>>>> +        # if we throw an exception during the test case.
>>>> +        def cleanup():
>>>> +            self.vscode.request_disconnect(terminateDebuggee=True)
>>>> +            self.vscode.terminate()
>>>> +
>>>> +        # Execute the cleanup function during test case tear down.
>>>> +        self.addTearDownHook(cleanup)
>>>> +
>>>> +        # Initialize and launch the program
>>>> +        self.vscode.request_initialize()
>>>> +        response = self.vscode.request_launch(
>>>> +            program,
>>>> +            args=args,
>>>> +            cwd=cwd,
>>>> +            env=env,
>>>> +            stopOnEntry=stopOnEntry,
>>>> +            disableASLR=disableASLR,
>>>> +            disableSTDIO=disableSTDIO,
>>>> +            shellExpandArguments=shellExpandArguments,
>>>> +            trace=trace,
>>>> +            initCommands=initCommands,
>>>> +            preRunCommands=preRunCommands,
>>>> +            stopCommands=stopCommands,
>>>> +            exitCommands=exitCommands,
>>>> +            sourcePath=sourcePath,
>>>> +            debuggerRoot=debuggerRoot)
>>>> +        if not (response and response['success']):
>>>> +            self.assertTrue(response['success'],
>>>> +                            'launch failed (%s)' % (response['message']))
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/Makefile
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/Makefile?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/Makefile?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/Makefile (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/Makefile Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,5 @@
>>>> +LEVEL = ../../../make
>>>> +
>>>> +C_SOURCES := main.c
>>>> +
>>>> +include $(LEVEL)/Makefile.rules
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/TestVSCode_stackTrace.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/TestVSCode_stackTrace.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/TestVSCode_stackTrace.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/TestVSCode_stackTrace.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/TestVSCode_stackTrace.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,159 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +
>>>> +
>>>> +class TestVSCode_stackTrace(lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +    name_key_path = ['name']
>>>> +    source_key_path = ['source', 'path']
>>>> +    line_key_path = ['line']
>>>> +
>>>> +    def verify_stackFrames(self, start_idx, stackFrames):
>>>> +        frame_idx = start_idx
>>>> +        for stackFrame in stackFrames:
>>>> +            # Don't care about frame above main
>>>> +            if frame_idx > 20:
>>>> +                return
>>>> +            self.verify_stackFrame(frame_idx, stackFrame)
>>>> +            frame_idx += 1
>>>> +
>>>> +    def verify_stackFrame(self, frame_idx, stackFrame):
>>>> +        frame_name = self.get_dict_value(stackFrame, self.name_key_path)
>>>> +        frame_source = self.get_dict_value(stackFrame, self.source_key_path)
>>>> +        frame_line = self.get_dict_value(stackFrame, self.line_key_path)
>>>> +        if frame_idx == 0:
>>>> +            expected_line = self.recurse_end
>>>> +            expected_name = 'recurse'
>>>> +        elif frame_idx < 20:
>>>> +            expected_line = self.recurse_call
>>>> +            expected_name = 'recurse'
>>>> +        else:
>>>> +            expected_line = self.recurse_invocation
>>>> +            expected_name = 'main'
>>>> +        self.assertTrue(frame_name == expected_name,
>>>> +                        'frame #%i name "%s" == "%s"' % (
>>>> +                            frame_idx, frame_name, expected_name))
>>>> +        self.assertTrue(frame_source == self.source_path,
>>>> +                        'frame #%i source "%s" == "%s"' % (
>>>> +                            frame_idx, frame_source, self.source_path))
>>>> +        self.assertTrue(frame_line == expected_line,
>>>> +                        'frame #%i line %i == %i' % (frame_idx, frame_line,
>>>> +                                                     expected_line))
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_stackTrace(self):
>>>> +        '''
>>>> +            Tests the 'stackTrace' packet and all its variants.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        source = 'main.c'
>>>> +        self.source_path = os.path.join(os.getcwd(), source)
>>>> +        self.recurse_end = line_number(source, 'recurse end')
>>>> +        self.recurse_call = line_number(source, 'recurse call')
>>>> +        self.recurse_invocation = line_number(source, 'recurse invocation')
>>>> +
>>>> +        lines = [self.recurse_end]
>>>> +
>>>> +        # Set breakoint at a point of deepest recuusion
>>>> +        breakpoint_ids = self.set_source_breakpoints(source, lines)
>>>> +        self.assertTrue(len(breakpoint_ids) == len(lines),
>>>> +                        "expect correct number of breakpoints")
>>>> +
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        startFrame = 0
>>>> +        # Verify we get all stack frames with no arguments
>>>> +        stackFrames = self.get_stackFrames()
>>>> +        frameCount = len(stackFrames)
>>>> +        self.assertTrue(frameCount >= 20,
>>>> +                        'verify we get at least 20 frames for all frames')
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Verify all stack frames by specifying startFrame = 0 and levels not
>>>> +        # specified
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame)
>>>> +        self.assertTrue(frameCount == len(stackFrames),
>>>> +                        ('verify same number of frames with startFrame=%i') % (
>>>> +                            startFrame))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Verify all stack frames by specifying startFrame = 0 and levels = 0
>>>> +        levels = 0
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(frameCount == len(stackFrames),
>>>> +                        ('verify same number of frames with startFrame=%i and'
>>>> +                         ' levels=%i') % (startFrame, levels))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Get only the first stack frame by sepcifying startFrame = 0 and
>>>> +        # levels = 1
>>>> +        levels = 1
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(levels == len(stackFrames),
>>>> +                        ('verify one frame with startFrame=%i and'
>>>> +                         ' levels=%i') % (startFrame, levels))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Get only the first 3 stack frames by sepcifying startFrame = 0 and
>>>> +        # levels = 3
>>>> +        levels = 3
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(levels == len(stackFrames),
>>>> +                        ('verify %i frames with startFrame=%i and'
>>>> +                         ' levels=%i') % (levels, startFrame, levels))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Get only the first 15 stack frames by sepcifying startFrame = 5 and
>>>> +        # levels = 16
>>>> +        startFrame = 5
>>>> +        levels = 16
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(levels == len(stackFrames),
>>>> +                        ('verify %i frames with startFrame=%i and'
>>>> +                         ' levels=%i') % (levels, startFrame, levels))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Verify we cap things correctly when we ask for too many frames
>>>> +        startFrame = 5
>>>> +        levels = 1000
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(len(stackFrames) == frameCount - startFrame,
>>>> +                        ('verify less than 1000 frames with startFrame=%i and'
>>>> +                         ' levels=%i') % (startFrame, levels))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Verify level=0 works with non-zerp start frame
>>>> +        startFrame = 5
>>>> +        levels = 0
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(len(stackFrames) == frameCount - startFrame,
>>>> +                        ('verify less than 1000 frames with startFrame=%i and'
>>>> +                         ' levels=%i') % (startFrame, levels))
>>>> +        self.verify_stackFrames(startFrame, stackFrames)
>>>> +
>>>> +        # Verify we get not frames when startFrame is too high
>>>> +        startFrame = 1000
>>>> +        levels = 1
>>>> +        stackFrames = self.get_stackFrames(startFrame=startFrame,
>>>> +                                           levels=levels)
>>>> +        self.assertTrue(0 == len(stackFrames),
>>>> +                        'verify zero frames with startFrame out of bounds')
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/main.c
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/main.c?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/main.c?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/main.c (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/stackTrace/main.c Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,13 @@
>>>> +#include <stdio.h>
>>>> +#include <unistd.h>
>>>> +
>>>> +int recurse(int x) {
>>>> +  if (x <= 1)
>>>> +    return 1; // recurse end
>>>> +  return recurse(x-1) + x; // recurse call
>>>> +}
>>>> +
>>>> +int main(int argc, char const *argv[]) {
>>>> +  recurse(20); // recurse invocation
>>>> +  return 0;
>>>> +}
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/Makefile
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/Makefile?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/Makefile?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/Makefile (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/Makefile Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,5 @@
>>>> +LEVEL = ../../../make
>>>> +
>>>> +CXX_SOURCES := main.cpp
>>>> +
>>>> +include $(LEVEL)/Makefile.rules
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/TestVSCode_step.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/TestVSCode_step.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/TestVSCode_step.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/TestVSCode_step.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/TestVSCode_step.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,78 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +
>>>> +
>>>> +class TestVSCode_step(lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_step(self):
>>>> +        '''
>>>> +            Tests the stepping in/out/over in threads.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        source = 'main.cpp'
>>>> +        # source_path = os.path.join(os.getcwd(), source)
>>>> +        breakpoint1_line = line_number(source, '// breakpoint 1')
>>>> +        lines = [breakpoint1_line]
>>>> +        # Set breakoint in the thread function so we can step the threads
>>>> +        breakpoint_ids = self.set_source_breakpoints(source, lines)
>>>> +        self.assertTrue(len(breakpoint_ids) == len(lines),
>>>> +                        "expect correct number of breakpoints")
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        threads = self.vscode.get_threads()
>>>> +        for thread in threads:
>>>> +            if 'reason' in thread:
>>>> +                reason = thread['reason']
>>>> +                if reason == 'breakpoint':
>>>> +                    # We have a thread that is stopped at our breakpoint.
>>>> +                    # Get the value of "x" and get the source file and line.
>>>> +                    # These will help us determine if we are stepping
>>>> +                    # correctly. If we step a thread correctly we will verify
>>>> +                    # the correct falue for x as it progresses through the
>>>> +                    # program.
>>>> +                    tid = thread['id']
>>>> +                    x1 = self.get_local_as_int('x', threadId=tid)
>>>> +                    (src1, line1) = self.get_source_and_line(threadId=tid)
>>>> +
>>>> +                    # Now step into the "recurse()" function call again and
>>>> +                    # verify, using the new value of "x" and the source file
>>>> +                    # and line if we stepped correctly
>>>> +                    self.stepIn(threadId=tid, waitForStop=True)
>>>> +                    x2 = self.get_local_as_int('x', threadId=tid)
>>>> +                    (src2, line2) = self.get_source_and_line(threadId=tid)
>>>> +                    self.assertTrue(x1 == x2 + 1, 'verify step in variable')
>>>> +                    self.assertTrue(line2 < line1, 'verify step in line')
>>>> +                    self.assertTrue(src1 == src2, 'verify step in source')
>>>> +
>>>> +                    # Now step out and verify
>>>> +                    self.stepOut(threadId=tid, waitForStop=True)
>>>> +                    x3 = self.get_local_as_int('x', threadId=tid)
>>>> +                    (src3, line3) = self.get_source_and_line(threadId=tid)
>>>> +                    self.assertTrue(x1 == x3, 'verify step out variable')
>>>> +                    self.assertTrue(line3 >= line1, 'verify step out line')
>>>> +                    self.assertTrue(src1 == src3, 'verify step in source')
>>>> +
>>>> +                    # Step over and verify
>>>> +                    self.stepOver(threadId=tid, waitForStop=True)
>>>> +                    x4 = self.get_local_as_int('x', threadId=tid)
>>>> +                    (src4, line4) = self.get_source_and_line(threadId=tid)
>>>> +                    self.assertTrue(x4 == x3, 'verify step over variable')
>>>> +                    self.assertTrue(line4 > line3, 'verify step over line')
>>>> +                    self.assertTrue(src1 == src4, 'verify step over source')
>>>> +                    # only step one thread that is at the breakpoint and stop
>>>> +                    break
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/main.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/main.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/main.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/main.cpp (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/step/main.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,16 @@
>>>> +#include <thread>
>>>> +
>>>> +int function(int x) {
>>>> +  if ((x % 2) == 0)
>>>> +    return function(x-1) + x; // breakpoint 1
>>>> +  else
>>>> +    return x;
>>>> +}
>>>> +
>>>> +int main(int argc, char const *argv[]) {
>>>> +  std::thread thread1(function, 2);
>>>> +  std::thread thread2(function, 4);
>>>> +  thread1.join();
>>>> +  thread2.join();
>>>> +  return 0;
>>>> +}
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/Makefile
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/Makefile?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/Makefile?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/Makefile (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/Makefile Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,5 @@
>>>> +LEVEL = ../../../make
>>>> +
>>>> +CXX_SOURCES := main.cpp
>>>> +
>>>> +include $(LEVEL)/Makefile.rules
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/TestVSCode_variables.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,224 @@
>>>> +"""
>>>> +Test lldb-vscode setBreakpoints request
>>>> +"""
>>>> +
>>>> +from __future__ import print_function
>>>> +
>>>> +import unittest2
>>>> +import vscode
>>>> +from lldbsuite.test.decorators import *
>>>> +from lldbsuite.test.lldbtest import *
>>>> +from lldbsuite.test import lldbutil
>>>> +import lldbvscode_testcase
>>>> +import os
>>>> +
>>>> +
>>>> +def make_buffer_verify_dict(start_idx, count, offset=0):
>>>> +    verify_dict = {}
>>>> +    for i in range(start_idx, start_idx + count):
>>>> +        verify_dict['[%i]' % (i)] = {'type': 'int', 'value': str(i+offset)}
>>>> +    return verify_dict
>>>> +
>>>> +
>>>> +class TestVSCode_variables(lldbvscode_testcase.VSCodeTestCaseBase):
>>>> +
>>>> +    mydir = TestBase.compute_mydir(__file__)
>>>> +
>>>> +    def verify_values(self, verify_dict, actual, varref_dict=None):
>>>> +        if 'equals' in verify_dict:
>>>> +            verify = verify_dict['equals']
>>>> +            for key in verify:
>>>> +                verify_value = verify[key]
>>>> +                actual_value = actual[key]
>>>> +                self.assertTrue(verify_value == actual_value,
>>>> +                                '"%s" keys don\'t match (%s != %s)' % (
>>>> +                                    key, actual_value, verify_value))
>>>> +        if 'startswith' in verify_dict:
>>>> +            verify = verify_dict['startswith']
>>>> +            for key in verify:
>>>> +                verify_value = verify[key]
>>>> +                actual_value = actual[key]
>>>> +                startswith = actual_value.startswith(verify_value)
>>>> +                self.assertTrue(startswith,
>>>> +                                ('"%s" value "%s" doesn\'t start with'
>>>> +                                 ' "%s")') % (
>>>> +                                    key, actual_value,
>>>> +                                    verify_value))
>>>> +        hasVariablesReference = 'variablesReference' in actual
>>>> +        varRef = None
>>>> +        if hasVariablesReference:
>>>> +            # Remember variable references in case we want to test further
>>>> +            # by using the evaluate name.
>>>> +            varRef = actual['variablesReference']
>>>> +            if varRef != 0 and varref_dict is not None:
>>>> +                varref_dict[actual['evaluateName']] = varRef
>>>> +        if ('hasVariablesReference' in verify_dict and
>>>> +                verify_dict['hasVariablesReference']):
>>>> +            self.assertTrue(hasVariablesReference,
>>>> +                            "verify variable reference")
>>>> +        if 'children' in verify_dict:
>>>> +            self.assertTrue(hasVariablesReference and varRef is not None and
>>>> +                            varRef != 0,
>>>> +                            ("children verify values specified for "
>>>> +                             "variable without children"))
>>>> +
>>>> +            response = self.vscode.request_variables(varRef)
>>>> +            self.verify_variables(verify_dict['children'],
>>>> +                                  response['body']['variables'],
>>>> +                                  varref_dict)
>>>> +
>>>> +    def verify_variables(self, verify_dict, variables, varref_dict=None):
>>>> +        for variable in variables:
>>>> +            name = variable['name']
>>>> +            self.assertTrue(name in verify_dict,
>>>> +                            'variable "%s" in verify dictionary' % (name))
>>>> +            self.verify_values(verify_dict[name], variable, varref_dict)
>>>> +
>>>> +    @skipIfWindows
>>>> +    @no_debug_info_test
>>>> +    def test_scopes_variables_setVariable_evaluate(self):
>>>> +        '''
>>>> +            Tests the "scopes", "variables", "setVariable", and "evaluate"
>>>> +            packets.
>>>> +        '''
>>>> +        program = self.getBuildArtifact("a.out")
>>>> +        self.build_and_launch(program)
>>>> +        source = 'main.cpp'
>>>> +        breakpoint1_line = line_number(source, '// breakpoint 1')
>>>> +        lines = [breakpoint1_line]
>>>> +        # Set breakoint in the thread function so we can step the threads
>>>> +        breakpoint_ids = self.set_source_breakpoints(source, lines)
>>>> +        self.assertTrue(len(breakpoint_ids) == len(lines),
>>>> +                        "expect correct number of breakpoints")
>>>> +        self.continue_to_breakpoints(breakpoint_ids)
>>>> +        locals = self.vscode.get_local_variables()
>>>> +        globals = self.vscode.get_global_variables()
>>>> +        buffer_children = make_buffer_verify_dict(0, 32)
>>>> +        verify_locals = {
>>>> +            'argc': {
>>>> +                'equals': {'type': 'int', 'value': '1'}
>>>> +            },
>>>> +            'argv': {
>>>> +                'equals': {'type': 'const char **'},
>>>> +                'startswith': {'value': '0x'},
>>>> +                'hasVariablesReference': True
>>>> +            },
>>>> +            'pt': {
>>>> +                'equals': {'type': 'PointType'},
>>>> +                'hasVariablesReference': True,
>>>> +                'children': {
>>>> +                    'x': {'equals': {'type': 'int', 'value': '11'}},
>>>> +                    'y': {'equals': {'type': 'int', 'value': '22'}},
>>>> +                    'buffer': {'children': buffer_children}
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +        verify_globals = {
>>>> +            's_local': {
>>>> +                'equals': {'type': 'float', 'value': '2.25'}
>>>> +            },
>>>> +            '::g_global': {
>>>> +                'equals': {'type': 'int', 'value': '123'}
>>>> +            },
>>>> +            's_global': {
>>>> +                'equals': {'type': 'int', 'value': '234'}
>>>> +            },
>>>> +        }
>>>> +        varref_dict = {}
>>>> +        self.verify_variables(verify_locals, locals, varref_dict)
>>>> +        self.verify_variables(verify_globals, globals, varref_dict)
>>>> +        # pprint.PrettyPrinter(indent=4).pprint(varref_dict)
>>>> +        # We need to test the functionality of the "variables" request as it
>>>> +        # has optional parameters like "start" and "count" to limit the number
>>>> +        # of variables that are fetched
>>>> +        varRef = varref_dict['pt.buffer']
>>>> +        response = self.vscode.request_variables(varRef)
>>>> +        self.verify_variables(buffer_children, response['body']['variables'])
>>>> +        # Verify setting start=0 in the arguments still gets all children
>>>> +        response = self.vscode.request_variables(varRef, start=0)
>>>> +        self.verify_variables(buffer_children, response['body']['variables'])
>>>> +        # Verify setting count=0 in the arguments still gets all children.
>>>> +        # If count is zero, it means to get all children.
>>>> +        response = self.vscode.request_variables(varRef, count=0)
>>>> +        self.verify_variables(buffer_children, response['body']['variables'])
>>>> +        # Verify setting count to a value that is too large in the arguments
>>>> +        # still gets all children, and no more
>>>> +        response = self.vscode.request_variables(varRef, count=1000)
>>>> +        self.verify_variables(buffer_children, response['body']['variables'])
>>>> +        # Verify setting the start index and count gets only the children we
>>>> +        # want
>>>> +        response = self.vscode.request_variables(varRef, start=5, count=5)
>>>> +        self.verify_variables(make_buffer_verify_dict(5, 5),
>>>> +                              response['body']['variables'])
>>>> +        # Verify setting the start index to a value that is out of range
>>>> +        # results in an empty list
>>>> +        response = self.vscode.request_variables(varRef, start=32, count=1)
>>>> +        self.assertTrue(len(response['body']['variables']) == 0,
>>>> +                        'verify we get no variable back for invalid start')
>>>> +
>>>> +        # Test evaluate
>>>> +        expressions = {
>>>> +            'pt.x': {
>>>> +                'equals': {'result': '11', 'type': 'int'},
>>>> +                'hasVariablesReference': False
>>>> +            },
>>>> +            'pt.buffer[2]': {
>>>> +                'equals': {'result': '2', 'type': 'int'},
>>>> +                'hasVariablesReference': False
>>>> +            },
>>>> +            'pt': {
>>>> +                'equals': {'type': 'PointType'},
>>>> +                'startswith': {'result': 'PointType @ 0x'},
>>>> +                'hasVariablesReference': True
>>>> +            },
>>>> +            'pt.buffer': {
>>>> +                'equals': {'type': 'int [32]'},
>>>> +                'startswith': {'result': 'int [32] @ 0x'},
>>>> +                'hasVariablesReference': True
>>>> +            },
>>>> +            'argv': {
>>>> +                'equals': {'type': 'const char **'},
>>>> +                'startswith': {'result': '0x'},
>>>> +                'hasVariablesReference': True
>>>> +            },
>>>> +            'argv[0]': {
>>>> +                'equals': {'type': 'const char *'},
>>>> +                'startswith': {'result': '0x'},
>>>> +                'hasVariablesReference': True
>>>> +            },
>>>> +            '2+3': {
>>>> +                'equals': {'result': '5', 'type': 'int'},
>>>> +                'hasVariablesReference': False
>>>> +            },
>>>> +        }
>>>> +        for expression in expressions:
>>>> +            response = self.vscode.request_evaluate(expression)
>>>> +            self.verify_values(expressions[expression], response['body'])
>>>> +
>>>> +        # Test setting variables
>>>> +        self.set_local('argc', 123)
>>>> +        argc = self.get_local_as_int('argc')
>>>> +        self.assertTrue(argc == 123,
>>>> +                        'verify argc was set to 123 (123 != %i)' % (argc))
>>>> +
>>>> +        self.set_local('argv', 0x1234)
>>>> +        argv = self.get_local_as_int('argv')
>>>> +        self.assertTrue(argv == 0x1234,
>>>> +                        'verify argv was set to 0x1234 (0x1234 != %#x)' % (
>>>> +                            argv))
>>>> +
>>>> +        # Set a variable value whose name is synthetic, like a variable index
>>>> +        # and verify the value by reading it
>>>> +        self.vscode.request_setVariable(varRef, "[0]", 100)
>>>> +        response = self.vscode.request_variables(varRef, start=0, count=1)
>>>> +        self.verify_variables(make_buffer_verify_dict(0, 1, 100),
>>>> +                              response['body']['variables'])
>>>> +
>>>> +        # Set a variable value whose name is a real child value, like "pt.x"
>>>> +        # and verify the value by reading it
>>>> +        varRef = varref_dict['pt']
>>>> +        self.vscode.request_setVariable(varRef, "x", 111)
>>>> +        response = self.vscode.request_variables(varRef, start=0, count=1)
>>>> +        value = response['body']['variables'][0]['value']
>>>> +        self.assertTrue(value == '111',
>>>> +                        'verify pt.x got set to 111 (111 != %s)' % (value))
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/main.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/main.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/main.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/main.cpp (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/variables/main.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,18 @@
>>>> +
>>>> +#define BUFFER_SIZE 32
>>>> +struct PointType {
>>>> +  int x;
>>>> +  int y;
>>>> +  int buffer[BUFFER_SIZE];
>>>> +};
>>>> +
>>>> +int g_global = 123;
>>>> +static int s_global = 234;
>>>> +
>>>> +int main(int argc, char const *argv[]) {
>>>> +  static float s_local = 2.25;
>>>> +  PointType pt = { 11,22, {0}};
>>>> +  for (int i=0; i<BUFFER_SIZE; ++i)
>>>> +    pt.buffer[i] = i;
>>>> +  return s_global - g_global - pt.y; // breakpoint 1
>>>> +}
>>>> 
>>>> Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py (added)
>>>> +++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,1084 @@
>>>> +#!/usr/bin/env python
>>>> +
>>>> +import binascii
>>>> +import json
>>>> +import optparse
>>>> +import os
>>>> +import pprint
>>>> +import socket
>>>> +import string
>>>> +import subprocess
>>>> +import sys
>>>> +import threading
>>>> +
>>>> +
>>>> +def dump_memory(base_addr, data, num_per_line, outfile):
>>>> +
>>>> +    data_len = len(data)
>>>> +    hex_string = binascii.hexlify(data)
>>>> +    addr = base_addr
>>>> +    ascii_str = ''
>>>> +    i = 0
>>>> +    while i < data_len:
>>>> +        outfile.write('0x%8.8x: ' % (addr + i))
>>>> +        bytes_left = data_len - i
>>>> +        if bytes_left >= num_per_line:
>>>> +            curr_data_len = num_per_line
>>>> +        else:
>>>> +            curr_data_len = bytes_left
>>>> +        hex_start_idx = i * 2
>>>> +        hex_end_idx = hex_start_idx + curr_data_len * 2
>>>> +        curr_hex_str = hex_string[hex_start_idx:hex_end_idx]
>>>> +        # 'curr_hex_str' now contains the hex byte string for the
>>>> +        # current line with no spaces between bytes
>>>> +        t = iter(curr_hex_str)
>>>> +        # Print hex bytes separated by space
>>>> +        outfile.write(' '.join(a + b for a, b in zip(t, t)))
>>>> +        # Print two spaces
>>>> +        outfile.write('  ')
>>>> +        # Calculate ASCII string for bytes into 'ascii_str'
>>>> +        ascii_str = ''
>>>> +        for j in range(i, i + curr_data_len):
>>>> +            ch = data[j]
>>>> +            if ch in string.printable and ch not in string.whitespace:
>>>> +                ascii_str += '%c' % (ch)
>>>> +            else:
>>>> +                ascii_str += '.'
>>>> +        # Print ASCII representation and newline
>>>> +        outfile.write(ascii_str)
>>>> +        i = i + curr_data_len
>>>> +        outfile.write('\n')
>>>> +
>>>> +
>>>> +def read_packet(f, verbose=False, trace_file=None):
>>>> +    '''Decode a JSON packet that starts with the content length and is
>>>> +       followed by the JSON bytes from a file 'f'
>>>> +    '''
>>>> +    line = f.readline()
>>>> +    if len(line) == 0:
>>>> +        return None
>>>> +
>>>> +    # Watch for line that starts with the prefix
>>>> +    prefix = 'Content-Length: '
>>>> +    if line.startswith(prefix):
>>>> +        # Decode length of JSON bytes
>>>> +        if verbose:
>>>> +            print('content: "%s"' % (line))
>>>> +        length = int(line[len(prefix):])
>>>> +        if verbose:
>>>> +            print('length: "%u"' % (length))
>>>> +        # Skip empty line
>>>> +        line = f.readline()
>>>> +        if verbose:
>>>> +            print('empty: "%s"' % (line))
>>>> +        # Read JSON bytes
>>>> +        json_str = f.read(length)
>>>> +        if verbose:
>>>> +            print('json: "%s"' % (json_str))
>>>> +        if trace_file:
>>>> +            trace_file.write('from adaptor:\n%s\n' % (json_str))
>>>> +        # Decode the JSON bytes into a python dictionary
>>>> +        return json.loads(json_str)
>>>> +
>>>> +    return None
>>>> +
>>>> +
>>>> +def packet_type_is(packet, packet_type):
>>>> +    return 'type' in packet and packet['type'] == packet_type
>>>> +
>>>> +
>>>> +def read_packet_thread(vs_comm):
>>>> +    done = False
>>>> +    while not done:
>>>> +        packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file)
>>>> +        if packet:
>>>> +            done = not vs_comm.handle_recv_packet(packet)
>>>> +        else:
>>>> +            done = True
>>>> +
>>>> +
>>>> +class DebugCommunication(object):
>>>> +
>>>> +    def __init__(self, recv, send):
>>>> +        self.trace_file = None
>>>> +        self.send = send
>>>> +        self.recv = recv
>>>> +        self.recv_packets = []
>>>> +        self.recv_condition = threading.Condition()
>>>> +        self.recv_thread = threading.Thread(target=read_packet_thread,
>>>> +                                            args=(self,))
>>>> +        self.process_event_body = None
>>>> +        self.exit_status = None
>>>> +        self.initialize_body = None
>>>> +        self.thread_stop_reasons = {}
>>>> +        self.sequence = 1
>>>> +        self.threads = None
>>>> +        self.recv_thread.start()
>>>> +        self.output_condition = threading.Condition()
>>>> +        self.output = {}
>>>> +        self.configuration_done_sent = False
>>>> +        self.frame_scopes = {}
>>>> +
>>>> +    @classmethod
>>>> +    def encode_content(cls, s):
>>>> +        return "Content-Length: %u\r\n\r\n%s" % (len(s), s)
>>>> +
>>>> +    @classmethod
>>>> +    def validate_response(cls, command, response):
>>>> +        if command['command'] != response['command']:
>>>> +            raise ValueError('command mismatch in response')
>>>> +        if command['seq'] != response['request_seq']:
>>>> +            raise ValueError('seq mismatch in response')
>>>> +
>>>> +    def get_output(self, category, timeout=0.0, clear=True):
>>>> +        self.output_condition.acquire()
>>>> +        output = None
>>>> +        if category in self.output:
>>>> +            output = self.output[category]
>>>> +            if clear:
>>>> +                del self.output[category]
>>>> +        elif timeout != 0.0:
>>>> +            self.output_condition.wait(timeout)
>>>> +            if category in self.output:
>>>> +                output = self.output[category]
>>>> +                if clear:
>>>> +                    del self.output[category]
>>>> +        self.output_condition.release()
>>>> +        return output
>>>> +
>>>> +    def handle_recv_packet(self, packet):
>>>> +        '''Called by the read thread that is waiting for all incoming packets
>>>> +           to store the incoming packet in "self.recv_packets" in a thread safe
>>>> +           way. This function will then signal the "self.recv_condition" to
>>>> +           indicate a new packet is available. Returns True if the caller
>>>> +           should keep calling this function for more packets.
>>>> +        '''
>>>> +        # Check the packet to see if is an event packet
>>>> +        keepGoing = True
>>>> +        packet_type = packet['type']
>>>> +        if packet_type == 'event':
>>>> +            event = packet['event']
>>>> +            body = None
>>>> +            if 'body' in packet:
>>>> +                body = packet['body']
>>>> +            # Handle the event packet and cache information from these packets
>>>> +            # as they come in
>>>> +            if event == 'output':
>>>> +                # Store any output we receive so clients can retrieve it later.
>>>> +                category = body['category']
>>>> +                output = body['output']
>>>> +                self.output_condition.acquire()
>>>> +                if category in self.output:
>>>> +                    self.output[category] += output
>>>> +                else:
>>>> +                    self.output[category] = output
>>>> +                self.output_condition.notify()
>>>> +                self.output_condition.release()
>>>> +                # no need to add 'output' packets to our packets list
>>>> +                return keepGoing
>>>> +            elif event == 'process':
>>>> +                # When a new process is attached or launched, remember the
>>>> +                # details that are available in the body of the event
>>>> +                self.process_event_body = body
>>>> +            elif event == 'stopped':
>>>> +                # Each thread that stops with a reason will send a
>>>> +                # 'stopped' event. We need to remember the thread stop
>>>> +                # reasons since the 'threads' command doesn't return
>>>> +                # that information.
>>>> +                self._process_stopped()
>>>> +                tid = body['threadId']
>>>> +                self.thread_stop_reasons[tid] = body
>>>> +        elif packet_type == 'response':
>>>> +            if packet['command'] == 'disconnect':
>>>> +                keepGoing = False
>>>> +        self.recv_condition.acquire()
>>>> +        self.recv_packets.append(packet)
>>>> +        self.recv_condition.notify()
>>>> +        self.recv_condition.release()
>>>> +        return keepGoing
>>>> +
>>>> +    def send_packet(self, command_dict, set_sequence=True):
>>>> +        '''Take the "command_dict" python dictionary and encode it as a JSON
>>>> +           string and send the contents as a packet to the VSCode debug
>>>> +           adaptor'''
>>>> +        # Set the sequence ID for this command automatically
>>>> +        if set_sequence:
>>>> +            command_dict['seq'] = self.sequence
>>>> +            self.sequence += 1
>>>> +        # Encode our command dictionary as a JSON string
>>>> +        json_str = json.dumps(command_dict, separators=(',', ':'))
>>>> +        if self.trace_file:
>>>> +            self.trace_file.write('to adaptor:\n%s\n' % (json_str))
>>>> +        length = len(json_str)
>>>> +        if length > 0:
>>>> +            # Send the encoded JSON packet and flush the 'send' file
>>>> +            self.send.write(self.encode_content(json_str))
>>>> +            self.send.flush()
>>>> +
>>>> +    def recv_packet(self, filter_type=None, filter_event=None, timeout=None):
>>>> +        '''Get a JSON packet from the VSCode debug adaptor. This function
>>>> +           assumes a thread that reads packets is running and will deliver
>>>> +           any received packets by calling handle_recv_packet(...). This
>>>> +           function will wait for the packet to arrive and return it when
>>>> +           it does.'''
>>>> +        while True:
>>>> +            self.recv_condition.acquire()
>>>> +            packet = None
>>>> +            while True:
>>>> +                for (i, curr_packet) in enumerate(self.recv_packets):
>>>> +                    packet_type = curr_packet['type']
>>>> +                    if filter_type is None or packet_type in filter_type:
>>>> +                        if (filter_event is None or
>>>> +                            (packet_type == 'event' and
>>>> +                             curr_packet['event'] in filter_event)):
>>>> +                            packet = self.recv_packets.pop(i)
>>>> +                            break
>>>> +                if packet:
>>>> +                    break
>>>> +                # Sleep until packet is received
>>>> +                len_before = len(self.recv_packets)
>>>> +                self.recv_condition.wait(timeout)
>>>> +                len_after = len(self.recv_packets)
>>>> +                if len_before == len_after:
>>>> +                    return None  # Timed out
>>>> +            self.recv_condition.release()
>>>> +            return packet
>>>> +
>>>> +        return None
>>>> +
>>>> +    def send_recv(self, command):
>>>> +        '''Send a command python dictionary as JSON and receive the JSON
>>>> +           response. Validates that the response is the correct sequence and
>>>> +           command in the reply. Any events that are received are added to the
>>>> +           events list in this object'''
>>>> +        self.send_packet(command)
>>>> +        done = False
>>>> +        while not done:
>>>> +            response = self.recv_packet(filter_type='response')
>>>> +            if response is None:
>>>> +                desc = 'no response for "%s"' % (command['command'])
>>>> +                raise ValueError(desc)
>>>> +            self.validate_response(command, response)
>>>> +            return response
>>>> +        return None
>>>> +
>>>> +    def wait_for_event(self, filter=None, timeout=None):
>>>> +        while True:
>>>> +            return self.recv_packet(filter_type='event', filter_event=filter,
>>>> +                                    timeout=timeout)
>>>> +        return None
>>>> +
>>>> +    def wait_for_stopped(self, timeout=None):
>>>> +        stopped_events = []
>>>> +        stopped_event = self.wait_for_event(filter=['stopped', 'exited'],
>>>> +                                            timeout=timeout)
>>>> +        exited = False
>>>> +        while stopped_event:
>>>> +            stopped_events.append(stopped_event)
>>>> +            # If we exited, then we are done
>>>> +            if stopped_event['event'] == 'exited':
>>>> +                self.exit_status = stopped_event['body']['exitCode']
>>>> +                exited = True
>>>> +                break
>>>> +            # Otherwise we stopped and there might be one or more 'stopped'
>>>> +            # events for each thread that stopped with a reason, so keep
>>>> +            # checking for more 'stopped' events and return all of them
>>>> +            stopped_event = self.wait_for_event(filter='stopped', timeout=0.25)
>>>> +        if exited:
>>>> +            self.threads = []
>>>> +        return stopped_events
>>>> +
>>>> +    def wait_for_exited(self):
>>>> +        event_dict = self.wait_for_event('exited')
>>>> +        if event_dict is None:
>>>> +            raise ValueError("didn't get stopped event")
>>>> +        return event_dict
>>>> +
>>>> +    def get_initialize_value(self, key):
>>>> +        '''Get a value for the given key if it there is a key/value pair in
>>>> +           the "initialize" request response body.
>>>> +        '''
>>>> +        if self.initialize_body and key in self.initialize_body:
>>>> +            return self.initialize_body[key]
>>>> +        return None
>>>> +
>>>> +    def get_threads(self):
>>>> +        if self.threads is None:
>>>> +            self.request_threads()
>>>> +        return self.threads
>>>> +
>>>> +    def get_thread_id(self, threadIndex=0):
>>>> +        '''Utility function to get the first thread ID in the thread list.
>>>> +           If the thread list is empty, then fetch the threads.
>>>> +        '''
>>>> +        if self.threads is None:
>>>> +            self.request_threads()
>>>> +        if self.threads and threadIndex < len(self.threads):
>>>> +            return self.threads[threadIndex]['id']
>>>> +        return None
>>>> +
>>>> +    def get_stackFrame(self, frameIndex=0, threadId=None):
>>>> +        '''Get a single "StackFrame" object from a "stackTrace" request and
>>>> +           return the "StackFrame as a python dictionary, or None on failure
>>>> +        '''
>>>> +        if threadId is None:
>>>> +            threadId = self.get_thread_id()
>>>> +        if threadId is None:
>>>> +            print('invalid threadId')
>>>> +            return None
>>>> +        response = self.request_stackTrace(threadId, startFrame=frameIndex,
>>>> +                                           levels=1)
>>>> +        if response:
>>>> +            return response['body']['stackFrames'][0]
>>>> +        print('invalid response')
>>>> +        return None
>>>> +
>>>> +    def get_scope_variables(self, scope_name, frameIndex=0, threadId=None):
>>>> +        stackFrame = self.get_stackFrame(frameIndex=frameIndex,
>>>> +                                         threadId=threadId)
>>>> +        if stackFrame is None:
>>>> +            return []
>>>> +        frameId = stackFrame['id']
>>>> +        if frameId in self.frame_scopes:
>>>> +            frame_scopes = self.frame_scopes[frameId]
>>>> +        else:
>>>> +            scopes_response = self.request_scopes(frameId)
>>>> +            frame_scopes = scopes_response['body']['scopes']
>>>> +            self.frame_scopes[frameId] = frame_scopes
>>>> +        for scope in frame_scopes:
>>>> +            if scope['name'] == scope_name:
>>>> +                varRef = scope['variablesReference']
>>>> +                variables_response = self.request_variables(varRef)
>>>> +                if variables_response:
>>>> +                    if 'body' in variables_response:
>>>> +                        body = variables_response['body']
>>>> +                        if 'variables' in body:
>>>> +                            vars = body['variables']
>>>> +                            return vars
>>>> +        return []
>>>> +
>>>> +    def get_global_variables(self, frameIndex=0, threadId=None):
>>>> +        return self.get_scope_variables('Globals', frameIndex=frameIndex,
>>>> +                                        threadId=threadId)
>>>> +
>>>> +    def get_local_variables(self, frameIndex=0, threadId=None):
>>>> +        return self.get_scope_variables('Locals', frameIndex=frameIndex,
>>>> +                                        threadId=threadId)
>>>> +
>>>> +    def get_local_variable(self, name, frameIndex=0, threadId=None):
>>>> +        locals = self.get_local_variables(frameIndex=frameIndex,
>>>> +                                          threadId=threadId)
>>>> +        for local in locals:
>>>> +            if 'name' in local and local['name'] == name:
>>>> +                return local
>>>> +        return None
>>>> +
>>>> +    def get_local_variable_value(self, name, frameIndex=0, threadId=None):
>>>> +        variable = self.get_local_variable(name, frameIndex=frameIndex,
>>>> +                                           threadId=threadId)
>>>> +        if variable and 'value' in variable:
>>>> +            return variable['value']
>>>> +        return None
>>>> +
>>>> +    def replay_packets(self, replay_file_path):
>>>> +        f = open(replay_file_path, 'r')
>>>> +        mode = 'invalid'
>>>> +        set_sequence = False
>>>> +        command_dict = None
>>>> +        while mode != 'eof':
>>>> +            if mode == 'invalid':
>>>> +                line = f.readline()
>>>> +                if line.startswith('to adapter:'):
>>>> +                    mode = 'send'
>>>> +                elif line.startswith('from adapter:'):
>>>> +                    mode = 'recv'
>>>> +            elif mode == 'send':
>>>> +                command_dict = read_packet(f)
>>>> +                # Skip the end of line that follows the JSON
>>>> +                f.readline()
>>>> +                if command_dict is None:
>>>> +                    raise ValueError('decode packet failed from replay file')
>>>> +                print('Sending:')
>>>> +                pprint.PrettyPrinter(indent=2).pprint(command_dict)
>>>> +                # raw_input('Press ENTER to send:')
>>>> +                self.send_packet(command_dict, set_sequence)
>>>> +                mode = 'invalid'
>>>> +            elif mode == 'recv':
>>>> +                print('Replay response:')
>>>> +                replay_response = read_packet(f)
>>>> +                # Skip the end of line that follows the JSON
>>>> +                f.readline()
>>>> +                pprint.PrettyPrinter(indent=2).pprint(replay_response)
>>>> +                actual_response = self.recv_packet()
>>>> +                if actual_response:
>>>> +                    type = actual_response['type']
>>>> +                    print('Actual response:')
>>>> +                    if type == 'response':
>>>> +                        self.validate_response(command_dict, actual_response)
>>>> +                    pprint.PrettyPrinter(indent=2).pprint(actual_response)
>>>> +                else:
>>>> +                    print("error: didn't get a valid response")
>>>> +                mode = 'invalid'
>>>> +
>>>> +    def request_attach(self, program=None, pid=None, waitFor=None, trace=None,
>>>> +                       initCommands=None, preRunCommands=None,
>>>> +                       stopCommands=None, exitCommands=None,
>>>> +                       attachCommands=None):
>>>> +        args_dict = {}
>>>> +        if pid is not None:
>>>> +            args_dict['pid'] = pid
>>>> +        if program is not None:
>>>> +            args_dict['program'] = program
>>>> +        if waitFor is not None:
>>>> +            args_dict['waitFor'] = waitFor
>>>> +        if trace:
>>>> +            args_dict['trace'] = trace
>>>> +        if initCommands:
>>>> +            args_dict['initCommands'] = initCommands
>>>> +        if preRunCommands:
>>>> +            args_dict['preRunCommands'] = preRunCommands
>>>> +        if stopCommands:
>>>> +            args_dict['stopCommands'] = stopCommands
>>>> +        if exitCommands:
>>>> +            args_dict['exitCommands'] = exitCommands
>>>> +        if attachCommands:
>>>> +            args_dict['attachCommands'] = attachCommands
>>>> +        command_dict = {
>>>> +            'command': 'attach',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_configurationDone(self):
>>>> +        command_dict = {
>>>> +            'command': 'configurationDone',
>>>> +            'type': 'request',
>>>> +            'arguments': {}
>>>> +        }
>>>> +        response = self.send_recv(command_dict)
>>>> +        if response:
>>>> +            self.configuration_done_sent = True
>>>> +        return response
>>>> +
>>>> +    def _process_stopped(self):
>>>> +        self.threads = None
>>>> +        self.frame_scopes = {}
>>>> +
>>>> +    def request_continue(self, threadId=None):
>>>> +        if self.exit_status is not None:
>>>> +            raise ValueError('request_continue called after process exited')
>>>> +        # If we have launched or attached, then the first continue is done by
>>>> +        # sending the 'configurationDone' request
>>>> +        if not self.configuration_done_sent:
>>>> +            return self.request_configurationDone()
>>>> +        args_dict = {}
>>>> +        if threadId is None:
>>>> +            threadId = self.get_thread_id()
>>>> +        args_dict['threadId'] = threadId
>>>> +        command_dict = {
>>>> +            'command': 'continue',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        response = self.send_recv(command_dict)
>>>> +        recv_packets = []
>>>> +        self.recv_condition.acquire()
>>>> +        for event in self.recv_packets:
>>>> +            if event['event'] != 'stopped':
>>>> +                recv_packets.append(event)
>>>> +        self.recv_packets = recv_packets
>>>> +        self.recv_condition.release()
>>>> +        return response
>>>> +
>>>> +    def request_disconnect(self, terminateDebuggee=None):
>>>> +        args_dict = {}
>>>> +        if terminateDebuggee is not None:
>>>> +            if terminateDebuggee:
>>>> +                args_dict['terminateDebuggee'] = True
>>>> +            else:
>>>> +                args_dict['terminateDebuggee'] = False
>>>> +        command_dict = {
>>>> +            'command': 'disconnect',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_evaluate(self, expression, frameIndex=0, threadId=None):
>>>> +        stackFrame = self.get_stackFrame(frameIndex=frameIndex,
>>>> +                                         threadId=threadId)
>>>> +        if stackFrame is None:
>>>> +            return []
>>>> +        args_dict = {
>>>> +            'expression': expression,
>>>> +            'frameId': stackFrame['id'],
>>>> +        }
>>>> +        command_dict = {
>>>> +            'command': 'evaluate',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_initialize(self):
>>>> +        command_dict = {
>>>> +            'command': 'initialize',
>>>> +            'type': 'request',
>>>> +            'arguments': {
>>>> +                'adapterID': 'lldb-native',
>>>> +                'clientID': 'vscode',
>>>> +                'columnsStartAt1': True,
>>>> +                'linesStartAt1': True,
>>>> +                'locale': 'en-us',
>>>> +                'pathFormat': 'path',
>>>> +                'supportsRunInTerminalRequest': True,
>>>> +                'supportsVariablePaging': True,
>>>> +                'supportsVariableType': True
>>>> +            }
>>>> +        }
>>>> +        response = self.send_recv(command_dict)
>>>> +        if response:
>>>> +            if 'body' in response:
>>>> +                self.initialize_body = response['body']
>>>> +        return response
>>>> +
>>>> +    def request_launch(self, program, args=None, cwd=None, env=None,
>>>> +                       stopOnEntry=False, disableASLR=True,
>>>> +                       disableSTDIO=False, shellExpandArguments=False,
>>>> +                       trace=False, initCommands=None, preRunCommands=None,
>>>> +                       stopCommands=None, exitCommands=None, sourcePath=None,
>>>> +                       debuggerRoot=None):
>>>> +        args_dict = {
>>>> +            'program': program
>>>> +        }
>>>> +        if args:
>>>> +            args_dict['args'] = args
>>>> +        if cwd:
>>>> +            args_dict['cwd'] = cwd
>>>> +        if env:
>>>> +            args_dict['env'] = env
>>>> +        if stopOnEntry:
>>>> +            args_dict['stopOnEntry'] = stopOnEntry
>>>> +        if disableASLR:
>>>> +            args_dict['disableASLR'] = disableASLR
>>>> +        if disableSTDIO:
>>>> +            args_dict['disableSTDIO'] = disableSTDIO
>>>> +        if shellExpandArguments:
>>>> +            args_dict['shellExpandArguments'] = shellExpandArguments
>>>> +        if trace:
>>>> +            args_dict['trace'] = trace
>>>> +        if initCommands:
>>>> +            args_dict['initCommands'] = initCommands
>>>> +        if preRunCommands:
>>>> +            args_dict['preRunCommands'] = preRunCommands
>>>> +        if stopCommands:
>>>> +            args_dict['stopCommands'] = stopCommands
>>>> +        if exitCommands:
>>>> +            args_dict['exitCommands'] = exitCommands
>>>> +        if sourcePath:
>>>> +            args_dict['sourcePath'] = sourcePath
>>>> +        if debuggerRoot:
>>>> +            args_dict['debuggerRoot'] = debuggerRoot
>>>> +        command_dict = {
>>>> +            'command': 'launch',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        response = self.send_recv(command_dict)
>>>> +
>>>> +        # Wait for a 'process' and 'initialized' event in any order
>>>> +        self.wait_for_event(filter=['process', 'initialized'])
>>>> +        self.wait_for_event(filter=['process', 'initialized'])
>>>> +        return response
>>>> +
>>>> +    def request_next(self, threadId):
>>>> +        if self.exit_status is not None:
>>>> +            raise ValueError('request_continue called after process exited')
>>>> +        args_dict = {'threadId': threadId}
>>>> +        command_dict = {
>>>> +            'command': 'next',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_stepIn(self, threadId):
>>>> +        if self.exit_status is not None:
>>>> +            raise ValueError('request_continue called after process exited')
>>>> +        args_dict = {'threadId': threadId}
>>>> +        command_dict = {
>>>> +            'command': 'stepIn',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_stepOut(self, threadId):
>>>> +        if self.exit_status is not None:
>>>> +            raise ValueError('request_continue called after process exited')
>>>> +        args_dict = {'threadId': threadId}
>>>> +        command_dict = {
>>>> +            'command': 'stepOut',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_pause(self, threadId=None):
>>>> +        if self.exit_status is not None:
>>>> +            raise ValueError('request_continue called after process exited')
>>>> +        if threadId is None:
>>>> +            threadId = self.get_thread_id()
>>>> +        args_dict = {'threadId': threadId}
>>>> +        command_dict = {
>>>> +            'command': 'pause',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_scopes(self, frameId):
>>>> +        args_dict = {'frameId': frameId}
>>>> +        command_dict = {
>>>> +            'command': 'scopes',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_setBreakpoints(self, file_path, line_array, condition=None,
>>>> +                               hitCondition=None):
>>>> +        (dir, base) = os.path.split(file_path)
>>>> +        breakpoints = []
>>>> +        for line in line_array:
>>>> +            bp = {'line': line}
>>>> +            if condition is not None:
>>>> +                bp['condition'] = condition
>>>> +            if hitCondition is not None:
>>>> +                bp['hitCondition'] = hitCondition
>>>> +            breakpoints.append(bp)
>>>> +        source_dict = {
>>>> +            'name': base,
>>>> +            'path': file_path
>>>> +        }
>>>> +        args_dict = {
>>>> +            'source': source_dict,
>>>> +            'breakpoints': breakpoints,
>>>> +            'lines': '%s' % (line_array),
>>>> +            'sourceModified': False,
>>>> +        }
>>>> +        command_dict = {
>>>> +            'command': 'setBreakpoints',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_setExceptionBreakpoints(self, filters):
>>>> +        args_dict = {'filters': filters}
>>>> +        command_dict = {
>>>> +            'command': 'setExceptionBreakpoints',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_setFunctionBreakpoints(self, names, condition=None,
>>>> +                                       hitCondition=None):
>>>> +        breakpoints = []
>>>> +        for name in names:
>>>> +            bp = {'name': name}
>>>> +            if condition is not None:
>>>> +                bp['condition'] = condition
>>>> +            if hitCondition is not None:
>>>> +                bp['hitCondition'] = hitCondition
>>>> +            breakpoints.append(bp)
>>>> +        args_dict = {'breakpoints': breakpoints}
>>>> +        command_dict = {
>>>> +            'command': 'setFunctionBreakpoints',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_stackTrace(self, threadId=None, startFrame=None, levels=None,
>>>> +                           dump=False):
>>>> +        if threadId is None:
>>>> +            threadId = self.get_thread_id()
>>>> +        args_dict = {'threadId': threadId}
>>>> +        if startFrame is not None:
>>>> +            args_dict['startFrame'] = startFrame
>>>> +        if levels is not None:
>>>> +            args_dict['levels'] = levels
>>>> +        command_dict = {
>>>> +            'command': 'stackTrace',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        response = self.send_recv(command_dict)
>>>> +        if dump:
>>>> +            for (idx, frame) in enumerate(response['body']['stackFrames']):
>>>> +                name = frame['name']
>>>> +                if 'line' in frame and 'source' in frame:
>>>> +                    source = frame['source']
>>>> +                    if 'sourceReference' not in source:
>>>> +                        if 'name' in source:
>>>> +                            source_name = source['name']
>>>> +                            line = frame['line']
>>>> +                            print("[%3u] %s @ %s:%u" % (idx, name, source_name,
>>>> +                                                        line))
>>>> +                            continue
>>>> +                print("[%3u] %s" % (idx, name))
>>>> +        return response
>>>> +
>>>> +    def request_threads(self):
>>>> +        '''Request a list of all threads and combine any information from any
>>>> +           "stopped" events since those contain more information about why a
>>>> +           thread actually stopped. Returns an array of thread dictionaries
>>>> +           with information about all threads'''
>>>> +        command_dict = {
>>>> +            'command': 'threads',
>>>> +            'type': 'request',
>>>> +            'arguments': {}
>>>> +        }
>>>> +        response = self.send_recv(command_dict)
>>>> +        body = response['body']
>>>> +        # Fill in "self.threads" correctly so that clients that call
>>>> +        # self.get_threads() or self.get_thread_id(...) can get information
>>>> +        # on threads when the process is stopped.
>>>> +        if 'threads' in body:
>>>> +            self.threads = body['threads']
>>>> +            for thread in self.threads:
>>>> +                # Copy the thread dictionary so we can add key/value pairs to
>>>> +                # it without affecfting the original info from the "threads"
>>>> +                # command.
>>>> +                tid = thread['id']
>>>> +                if tid in self.thread_stop_reasons:
>>>> +                    thread_stop_info = self.thread_stop_reasons[tid]
>>>> +                    copy_keys = ['reason', 'description', 'text']
>>>> +                    for key in copy_keys:
>>>> +                        if key in thread_stop_info:
>>>> +                            thread[key] = thread_stop_info[key]
>>>> +        else:
>>>> +            self.threads = None
>>>> +        return response
>>>> +
>>>> +    def request_variables(self, variablesReference, start=None, count=None):
>>>> +        args_dict = {'variablesReference': variablesReference}
>>>> +        if start is not None:
>>>> +            args_dict['start'] = start
>>>> +        if count is not None:
>>>> +            args_dict['count'] = count
>>>> +        command_dict = {
>>>> +            'command': 'variables',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_setVariable(self, containingVarRef, name, value, id=None):
>>>> +        args_dict = {
>>>> +            'variablesReference': containingVarRef,
>>>> +            'name': name,
>>>> +            'value': str(value)
>>>> +        }
>>>> +        if id is not None:
>>>> +            args_dict['id'] = id
>>>> +        command_dict = {
>>>> +            'command': 'setVariable',
>>>> +            'type': 'request',
>>>> +            'arguments': args_dict
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def request_testGetTargetBreakpoints(self):
>>>> +        '''A request packet used in the LLDB test suite to get all currently
>>>> +           set breakpoint infos for all breakpoints currently set in the
>>>> +           target.
>>>> +        '''
>>>> +        command_dict = {
>>>> +            'command': '_testGetTargetBreakpoints',
>>>> +            'type': 'request',
>>>> +            'arguments': {}
>>>> +        }
>>>> +        return self.send_recv(command_dict)
>>>> +
>>>> +    def terminate(self):
>>>> +        self.send.close()
>>>> +        # self.recv.close()
>>>> +
>>>> +
>>>> +class DebugAdaptor(DebugCommunication):
>>>> +    def __init__(self, executable=None, port=None):
>>>> +        self.process = None
>>>> +        if executable is not None:
>>>> +            self.process = subprocess.Popen([executable],
>>>> +                                            stdin=subprocess.PIPE,
>>>> +                                            stdout=subprocess.PIPE,
>>>> +                                            stderr=subprocess.PIPE)
>>>> +            DebugCommunication.__init__(self, self.process.stdout,
>>>> +                                        self.process.stdin)
>>>> +        elif port is not None:
>>>> +            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>>> +            s.connect(('127.0.0.1', port))
>>>> +            DebugCommunication.__init__(self, s.makefile('r'), s.makefile('w'))
>>>> +
>>>> +    def get_pid(self):
>>>> +        if self.process:
>>>> +            return self.process.pid
>>>> +        return -1
>>>> +
>>>> +    def terminate(self):
>>>> +        super(DebugAdaptor, self).terminate()
>>>> +        if self.process is not None:
>>>> +            self.process.terminate()
>>>> +            self.process.wait()
>>>> +            self.process = None
>>>> +
>>>> +
>>>> +def attach_options_specified(options):
>>>> +    if options.pid is not None:
>>>> +        return True
>>>> +    if options.waitFor:
>>>> +        return True
>>>> +    if options.attach:
>>>> +        return True
>>>> +    if options.attachCmds:
>>>> +        return True
>>>> +    return False
>>>> +
>>>> +
>>>> +def run_vscode(dbg, args, options):
>>>> +    dbg.request_initialize()
>>>> +    if attach_options_specified(options):
>>>> +        response = dbg.request_attach(program=options.program,
>>>> +                                      pid=options.pid,
>>>> +                                      waitFor=options.waitFor,
>>>> +                                      attachCommands=options.attachCmds,
>>>> +                                      initCommands=options.initCmds,
>>>> +                                      preRunCommands=options.preRunCmds,
>>>> +                                      stopCommands=options.stopCmds,
>>>> +                                      exitCommands=options.exitCmds)
>>>> +    else:
>>>> +        response = dbg.request_launch(options.program,
>>>> +                                      args=args,
>>>> +                                      env=options.envs,
>>>> +                                      cwd=options.workingDir,
>>>> +                                      debuggerRoot=options.debuggerRoot,
>>>> +                                      sourcePath=options.sourcePath,
>>>> +                                      initCommands=options.initCmds,
>>>> +                                      preRunCommands=options.preRunCmds,
>>>> +                                      stopCommands=options.stopCmds,
>>>> +                                      exitCommands=options.exitCmds)
>>>> +
>>>> +    if response['success']:
>>>> +        if options.sourceBreakpoints:
>>>> +            source_to_lines = {}
>>>> +            for file_line in options.sourceBreakpoints:
>>>> +                (path, line) = file_line.split(':')
>>>> +                if len(path) == 0 or len(line) == 0:
>>>> +                    print('error: invalid source with line "%s"' %
>>>> +                          (file_line))
>>>> +
>>>> +                else:
>>>> +                    if path in source_to_lines:
>>>> +                        source_to_lines[path].append(int(line))
>>>> +                    else:
>>>> +                        source_to_lines[path] = [int(line)]
>>>> +            for source in source_to_lines:
>>>> +                dbg.request_setBreakpoints(source, source_to_lines[source])
>>>> +        if options.funcBreakpoints:
>>>> +            dbg.request_setFunctionBreakpoints(options.funcBreakpoints)
>>>> +        dbg.request_configurationDone()
>>>> +        dbg.wait_for_stopped()
>>>> +    else:
>>>> +        if 'message' in response:
>>>> +            print(response['message'])
>>>> +    dbg.request_disconnect(terminateDebuggee=True)
>>>> +
>>>> +
>>>> +def main():
>>>> +    parser = optparse.OptionParser(
>>>> +        description=('A testing framework for the Visual Studio Code Debug '
>>>> +                     'Adaptor protocol'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--vscode',
>>>> +        type='string',
>>>> +        dest='vscode_path',
>>>> +        help=('The path to the a command line program that implements the '
>>>> +              'Visual Studio Code Debug Adaptor protocol.'),
>>>> +        default=None)
>>>> +
>>>> +    parser.add_option(
>>>> +        '--program',
>>>> +        type='string',
>>>> +        dest='program',
>>>> +        help='The path to the program to debug.',
>>>> +        default=None)
>>>> +
>>>> +    parser.add_option(
>>>> +        '--workingDir',
>>>> +        type='string',
>>>> +        dest='workingDir',
>>>> +        default=None,
>>>> +        help='Set the working directory for the process we launch.')
>>>> +
>>>> +    parser.add_option(
>>>> +        '--sourcePath',
>>>> +        type='string',
>>>> +        dest='sourcePath',
>>>> +        default=None,
>>>> +        help=('Set the relative source root for any debug info that has '
>>>> +              'relative paths in it.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--debuggerRoot',
>>>> +        type='string',
>>>> +        dest='debuggerRoot',
>>>> +        default=None,
>>>> +        help=('Set the working directory for lldb-vscode for any object files '
>>>> +              'with relative paths in the Mach-o debug map.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '-r', '--replay',
>>>> +        type='string',
>>>> +        dest='replay',
>>>> +        help=('Specify a file containing a packet log to replay with the '
>>>> +              'current Visual Studio Code Debug Adaptor executable.'),
>>>> +        default=None)
>>>> +
>>>> +    parser.add_option(
>>>> +        '-g', '--debug',
>>>> +        action='store_true',
>>>> +        dest='debug',
>>>> +        default=False,
>>>> +        help='Pause waiting for a debugger to attach to the debug adaptor')
>>>> +
>>>> +    parser.add_option(
>>>> +        '--port',
>>>> +        type='int',
>>>> +        dest='port',
>>>> +        help="Attach a socket to a port instead of using STDIN for VSCode",
>>>> +        default=None)
>>>> +
>>>> +    parser.add_option(
>>>> +        '--pid',
>>>> +        type='int',
>>>> +        dest='pid',
>>>> +        help="The process ID to attach to",
>>>> +        default=None)
>>>> +
>>>> +    parser.add_option(
>>>> +        '--attach',
>>>> +        action='store_true',
>>>> +        dest='attach',
>>>> +        default=False,
>>>> +        help=('Specify this option to attach to a process by name. The '
>>>> +              'process name is the basanme of the executable specified with '
>>>> +              'the --program option.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '-f', '--function-bp',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='funcBreakpoints',
>>>> +        help=('Specify the name of a function to break at. '
>>>> +              'Can be specified more than once.'),
>>>> +        default=[])
>>>> +
>>>> +    parser.add_option(
>>>> +        '-s', '--source-bp',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='sourceBreakpoints',
>>>> +        default=[],
>>>> +        help=('Specify source breakpoints to set in the format of '
>>>> +              '<source>:<line>. '
>>>> +              'Can be specified more than once.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--attachCommand',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='attachCmds',
>>>> +        default=[],
>>>> +        help=('Specify a LLDB command that will attach to a process. '
>>>> +              'Can be specified more than once.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--initCommand',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='initCmds',
>>>> +        default=[],
>>>> +        help=('Specify a LLDB command that will be executed before the target '
>>>> +              'is created. Can be specified more than once.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--preRunCommand',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='preRunCmds',
>>>> +        default=[],
>>>> +        help=('Specify a LLDB command that will be executed after the target '
>>>> +              'has been created. Can be specified more than once.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--stopCommand',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='stopCmds',
>>>> +        default=[],
>>>> +        help=('Specify a LLDB command that will be executed each time the'
>>>> +              'process stops. Can be specified more than once.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--exitCommand',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='exitCmds',
>>>> +        default=[],
>>>> +        help=('Specify a LLDB command that will be executed when the process '
>>>> +              'exits. Can be specified more than once.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--env',
>>>> +        type='string',
>>>> +        action='append',
>>>> +        dest='envs',
>>>> +        default=[],
>>>> +        help=('Specify environment variables to pass to the launched '
>>>> +              'process.'))
>>>> +
>>>> +    parser.add_option(
>>>> +        '--waitFor',
>>>> +        action='store_true',
>>>> +        dest='waitFor',
>>>> +        default=False,
>>>> +        help=('Wait for the next process to be launched whose name matches '
>>>> +              'the basename of the program specified with the --program '
>>>> +              'option'))
>>>> +
>>>> +    (options, args) = parser.parse_args(sys.argv[1:])
>>>> +
>>>> +    if options.vscode_path is None and options.port is None:
>>>> +        print('error: must either specify a path to a Visual Studio Code '
>>>> +              'Debug Adaptor vscode executable path using the --vscode '
>>>> +              'option, or a port to attach to for an existing lldb-vscode '
>>>> +              'using the --port option')
>>>> +        return
>>>> +    dbg = DebugAdaptor(executable=options.vscode_path, port=options.port)
>>>> +    if options.debug:
>>>> +        raw_input('Waiting for debugger to attach pid "%i"' % (
>>>> +                  dbg.get_pid()))
>>>> +    if options.replay:
>>>> +        dbg.replay_packets(options.replay)
>>>> +    else:
>>>> +        run_vscode(dbg, args, options)
>>>> +    dbg.terminate()
>>>> +
>>>> +
>>>> +if __name__ == '__main__':
>>>> +    main()
>>>> 
>>>> Modified: lldb/trunk/tools/CMakeLists.txt
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/CMakeLists.txt?rev=339911&r1=339910&r2=339911&view=diff <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/CMakeLists.txt?rev=339911&r1=339910&r2=339911&view=diff>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/CMakeLists.txt (original)
>>>> +++ lldb/trunk/tools/CMakeLists.txt Thu Aug 16 10:59:38 2018
>>>> @@ -5,6 +5,7 @@ endif()
>>>> add_subdirectory(argdumper)
>>>> add_subdirectory(driver)
>>>> add_subdirectory(lldb-mi)
>>>> +add_subdirectory(lldb-vscode)
>>>> if (LLDB_CAN_USE_LLDB_SERVER)
>>>>   add_subdirectory(lldb-server)
>>>> endif()
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/BreakpointBase.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/BreakpointBase.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/BreakpointBase.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/BreakpointBase.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/BreakpointBase.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,37 @@
>>>> +//===-- BreakpointBase.cpp --------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include "BreakpointBase.h"
>>>> +#include "llvm/ADT/StringExtras.h"
>>>> +
>>>> +using namespace lldb_vscode;
>>>> +
>>>> +BreakpointBase::BreakpointBase(const llvm::json::Object &obj)
>>>> +    : condition(GetString(obj, "condition")),
>>>> +      hitCondition(GetString(obj, "hitCondition")),
>>>> +      logMessage(GetString(obj, "logMessage")) {}
>>>> +
>>>> +void BreakpointBase::SetCondition() { bp.SetCondition(condition.c_str()); }
>>>> +
>>>> +void BreakpointBase::SetHitCondition() {  
>>>> +  uint64_t hitCount = 0;
>>>> +  if (llvm::to_integer(hitCondition, hitCount))
>>>> +    bp.SetIgnoreCount(hitCount - 1);
>>>> +}
>>>> +
>>>> +void BreakpointBase::UpdateBreakpoint(const BreakpointBase &request_bp) {
>>>> +  if (condition != request_bp.condition) {
>>>> +    condition = request_bp.condition;
>>>> +    SetCondition();
>>>> +  }
>>>> +  if (hitCondition != request_bp.hitCondition) {
>>>> +    hitCondition = request_bp.hitCondition;
>>>> +    SetHitCondition();
>>>> +  }
>>>> +}
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/BreakpointBase.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/BreakpointBase.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/BreakpointBase.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/BreakpointBase.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/BreakpointBase.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,44 @@
>>>> +//===-- BreakpointBase.h ----------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_BREAKPOINTBASE_H_
>>>> +#define LLDBVSCODE_BREAKPOINTBASE_H_
>>>> +
>>>> +#include "JSONUtils.h"
>>>> +#include "lldb/API/SBBreakpoint.h"
>>>> +#include "llvm/Support/JSON.h"
>>>> +#include <string>
>>>> +
>>>> +namespace lldb_vscode {
>>>> +  
>>>> +struct BreakpointBase {
>>>> +
>>>> +  // An optional expression for conditional breakpoints.
>>>> +  std::string condition;
>>>> +  // An optional expression that controls how many hits of the breakpoint are
>>>> +  // ignored. The backend is expected to interpret the expression as needed
>>>> +  std::string hitCondition;
>>>> +  // If this attribute exists and is non-empty, the backend must not 'break'
>>>> +  // (stop) but log the message instead. Expressions within {} are
>>>> +  // interpolated.
>>>> +  std::string logMessage;
>>>> +  // The LLDB breakpoint associated wit this source breakpoint
>>>> +  lldb::SBBreakpoint bp;
>>>> +
>>>> +  BreakpointBase() = default;
>>>> +  BreakpointBase(const llvm::json::Object &obj);
>>>> +
>>>> +  void SetCondition();
>>>> +  void SetHitCondition();
>>>> +  void UpdateBreakpoint(const BreakpointBase &request_bp);
>>>> +};
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/CMakeLists.txt
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/CMakeLists.txt?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/CMakeLists.txt?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/CMakeLists.txt (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/CMakeLists.txt Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,30 @@
>>>> +if ( CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "NetBSD" )
>>>> +  add_definitions( -DIMPORT_LIBLLDB )
>>>> +  list(APPEND extra_libs lldbHost)
>>>> +endif ()
>>>> +
>>>> +if (HAVE_LIBPTHREAD)
>>>> +  list(APPEND extra_libs pthread)
>>>> +endif ()
>>>> +
>>>> +# We need to include the llvm components we depend on manually, as liblldb does
>>>> +# not re-export those.
>>>> +set(LLVM_LINK_COMPONENTS Support)
>>>> +add_lldb_tool(lldb-vscode
>>>> +  lldb-vscode.cpp
>>>> +  BreakpointBase.cpp
>>>> +  ExceptionBreakpoint.cpp
>>>> +  FunctionBreakpoint.cpp
>>>> +  JSONUtils.cpp
>>>> +  LLDBUtils.cpp
>>>> +  SourceBreakpoint.cpp
>>>> +  VSCode.cpp
>>>> +
>>>> +  LINK_LIBS
>>>> +    liblldb
>>>> +    ${host_lib}
>>>> +    ${extra_libs}
>>>> +
>>>> +  LINK_COMPONENTS
>>>> +    Support
>>>> +  )
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,32 @@
>>>> +//===-- ExceptionBreakpoint.cpp ---------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include "ExceptionBreakpoint.h"
>>>> +#include "VSCode.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +void ExceptionBreakpoint::SetBreakpoint() {
>>>> +  if (bp.IsValid())
>>>> +    return;
>>>> +  bool catch_value = filter.find("_catch") != std::string::npos;
>>>> +  bool throw_value = filter.find("_throw") != std::string::npos;
>>>> +  bp = g_vsc.target.BreakpointCreateForException(language, catch_value,
>>>> +                                                 throw_value);
>>>> +}
>>>> +
>>>> +void ExceptionBreakpoint::ClearBreakpoint() {
>>>> +  if (!bp.IsValid())
>>>> +    return;
>>>> +  g_vsc.target.BreakpointDelete(bp.GetID());
>>>> +  bp = lldb::SBBreakpoint();
>>>> +}
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/ExceptionBreakpoint.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,38 @@
>>>> +//===-- ExceptionBreakpoint.h -----------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_EXCEPTIONBREAKPOINT_H_
>>>> +#define LLDBVSCODE_EXCEPTIONBREAKPOINT_H_
>>>> +
>>>> +#include <string>
>>>> +
>>>> +#include "lldb/API/SBBreakpoint.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +struct ExceptionBreakpoint {
>>>> +  std::string filter;
>>>> +  std::string label;
>>>> +  lldb::LanguageType language;
>>>> +  bool default_value;
>>>> +  lldb::SBBreakpoint bp;
>>>> +  ExceptionBreakpoint(std::string f, std::string l, lldb::LanguageType lang) :
>>>> +    filter(std::move(f)),
>>>> +    label(std::move(l)),
>>>> +    language(lang),
>>>> +    default_value(false),
>>>> +    bp() {}
>>>> +
>>>> +  void SetBreakpoint();
>>>> +  void ClearBreakpoint();
>>>> +};
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,28 @@
>>>> +//===-- FunctionBreakpoint.cpp ----------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include "FunctionBreakpoint.h"
>>>> +#include "VSCode.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +FunctionBreakpoint::FunctionBreakpoint(const llvm::json::Object &obj)
>>>> +    : BreakpointBase(obj), functionName(GetString(obj, "name")) {}
>>>> +
>>>> +void FunctionBreakpoint::SetBreakpoint() {
>>>> +  if (functionName.empty())
>>>> +    return;
>>>> +  bp = g_vsc.target.BreakpointCreateByName(functionName.c_str());
>>>> +  if (!condition.empty())
>>>> +    SetCondition();
>>>> +  if (!hitCondition.empty())
>>>> +    SetHitCondition();
>>>> +}
>>>> +
>>>> +}
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/FunctionBreakpoint.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,29 @@
>>>> +//===-- FunctionBreakpoint.h ------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_FUNCTIONBREAKPOINT_H_
>>>> +#define LLDBVSCODE_FUNCTIONBREAKPOINT_H_
>>>> +
>>>> +#include "BreakpointBase.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +struct FunctionBreakpoint : public BreakpointBase {
>>>> +  std::string functionName;
>>>> +
>>>> +  FunctionBreakpoint() = default;
>>>> +  FunctionBreakpoint(const llvm::json::Object &obj);
>>>> +
>>>> +  // Set this breakpoint in LLDB as a new breakpoint
>>>> +  void SetBreakpoint();
>>>> +};
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/JSONUtils.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/JSONUtils.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/JSONUtils.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/JSONUtils.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/JSONUtils.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,882 @@
>>>> +//===-- JSONUtils.cpp -------------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include "llvm/Support/FormatAdapters.h"
>>>> +
>>>> +#include "lldb/API/SBBreakpoint.h"
>>>> +#include "lldb/API/SBBreakpointLocation.h"
>>>> +#include "lldb/API/SBValue.h"
>>>> +
>>>> +#include "ExceptionBreakpoint.h"
>>>> +#include "JSONUtils.h"
>>>> +#include "LLDBUtils.h"
>>>> +#include "VSCode.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +llvm::StringRef GetAsString(const llvm::json::Value &value) {
>>>> +  if (auto s = value.getAsString())
>>>> +    return *s;
>>>> +  return llvm::StringRef();
>>>> +}
>>>> +
>>>> +// Gets a string from a JSON object using the key, or returns an empty string.
>>>> +llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key) {
>>>> +  if (auto value = obj.getString(key))
>>>> +    return GetAsString(*value);
>>>> +  return llvm::StringRef();
>>>> +}
>>>> +
>>>> +llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key) {
>>>> +  if (obj == nullptr)
>>>> +    return llvm::StringRef();
>>>> +  return GetString(*obj, key);
>>>> +}
>>>> +
>>>> +// Gets an unsigned integer from a JSON object using the key, or returns the
>>>> +// specified fail value.
>>>> +uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key,
>>>> +                     uint64_t fail_value) {
>>>> +  if (auto value = obj.getInteger(key))
>>>> +    return (uint64_t)*value;
>>>> +  return fail_value;
>>>> +}
>>>> +
>>>> +uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key,
>>>> +                     uint64_t fail_value) {
>>>> +  if (obj == nullptr)
>>>> +    return fail_value;
>>>> +  return GetUnsigned(*obj, key, fail_value);
>>>> +}
>>>> +
>>>> +bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
>>>> +                bool fail_value) {
>>>> +  if (auto value = obj.getBoolean(key))
>>>> +    return *value;
>>>> +  if (auto value = obj.getInteger(key))
>>>> +    return *value != 0;
>>>> +  return fail_value;
>>>> +}
>>>> +
>>>> +bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key,
>>>> +                bool fail_value) {
>>>> +  if (obj == nullptr)
>>>> +    return fail_value;
>>>> +  return GetBoolean(*obj, key, fail_value);
>>>> +}
>>>> +
>>>> +int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key,
>>>> +                  int64_t fail_value) {
>>>> +  if (auto value = obj.getInteger(key))
>>>> +    return *value;
>>>> +  return fail_value;
>>>> +}
>>>> +
>>>> +int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key,
>>>> +                  int64_t fail_value) {
>>>> +  if (obj == nullptr)
>>>> +    return fail_value;
>>>> +  return GetSigned(*obj, key, fail_value);
>>>> +}
>>>> +
>>>> +bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) {
>>>> +  if (obj.find(key) != obj.end())
>>>> +    return true;
>>>> +  return false;
>>>> +}
>>>> +
>>>> +std::vector<std::string> GetStrings(const llvm::json::Object *obj,
>>>> +                                    llvm::StringRef key) {
>>>> +  std::vector<std::string> strs;
>>>> +  auto json_array = obj->getArray(key);
>>>> +  if (!json_array)
>>>> +    return strs;
>>>> +  for (const auto &value : *json_array) {
>>>> +    switch (value.kind()) {
>>>> +    case llvm::json::Value::String:
>>>> +      strs.push_back(value.getAsString()->str());
>>>> +      break;
>>>> +    case llvm::json::Value::Number:
>>>> +    case llvm::json::Value::Boolean: {
>>>> +      std::string s;
>>>> +      llvm::raw_string_ostream strm(s);
>>>> +      strm << value;
>>>> +      strs.push_back(strm.str());
>>>> +      break;
>>>> +    }
>>>> +    case llvm::json::Value::Null:
>>>> +    case llvm::json::Value::Object:
>>>> +    case llvm::json::Value::Array:
>>>> +      break;
>>>> +    }
>>>> +  }
>>>> +  return strs;
>>>> +}
>>>> +
>>>> +void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
>>>> +                    llvm::StringRef key) {
>>>> +  
>>>> +  llvm::StringRef value = v.GetValue();
>>>> +  llvm::StringRef summary = v.GetSummary();
>>>> +  llvm::StringRef type_name = v.GetType().GetDisplayTypeName();
>>>> +  
>>>> +  std::string result;
>>>> +  llvm::raw_string_ostream strm(result);
>>>> +  if (!value.empty()) {
>>>> +    strm << value;
>>>> +    if (!summary.empty())
>>>> +      strm << ' ' << summary;
>>>> +  } else if (!summary.empty()) {
>>>> +    strm << ' ' << summary;
>>>> +  } else if (!type_name.empty()) {
>>>> +    strm << type_name;
>>>> +    lldb::addr_t address = v.GetLoadAddress();
>>>> +    if (address != LLDB_INVALID_ADDRESS)
>>>> +      strm << " @ " << llvm::format_hex(address, 0);
>>>> +  }
>>>> +  strm.flush();
>>>> +  object.try_emplace(key, result);
>>>> +}
>>>> +
>>>> +void FillResponse(const llvm::json::Object &request,
>>>> +                  llvm::json::Object &response) {
>>>> +  // Fill in all of the needed response fields to a "request" and set "success"
>>>> +  // to true by default.
>>>> +  response.try_emplace("type", "response");
>>>> +  response.try_emplace("seq", (int64_t)0);
>>>> +  response.try_emplace("command", GetString(request, "command"));
>>>> +  const int64_t seq = GetSigned(request, "seq", 0);
>>>> +  response.try_emplace("request_seq", seq);
>>>> +  response.try_emplace("success", true);
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "Scope": {
>>>> +//   "type": "object",
>>>> +//   "description": "A Scope is a named container for variables. Optionally
>>>> +//                   a scope can map to a source or a range within a source.",
>>>> +//   "properties": {
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "Name of the scope such as 'Arguments', 'Locals'."
>>>> +//     },
>>>> +//     "variablesReference": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The variables of this scope can be retrieved by
>>>> +//                       passing the value of variablesReference to the
>>>> +//                       VariablesRequest."
>>>> +//     },
>>>> +//     "namedVariables": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The number of named variables in this scope. The
>>>> +//                       client can use this optional information to present
>>>> +//                       the variables in a paged UI and fetch them in chunks."
>>>> +//     },
>>>> +//     "indexedVariables": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The number of indexed variables in this scope. The
>>>> +//                       client can use this optional information to present
>>>> +//                       the variables in a paged UI and fetch them in chunks."
>>>> +//     },
>>>> +//     "expensive": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "If true, the number of variables in this scope is
>>>> +//                       large or expensive to retrieve."
>>>> +//     },
>>>> +//     "source": {
>>>> +//       "$ref": "#/definitions/Source",
>>>> +//       "description": "Optional source for this scope."
>>>> +//     },
>>>> +//     "line": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Optional start line of the range covered by this
>>>> +//                       scope."
>>>> +//     },
>>>> +//     "column": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Optional start column of the range covered by this
>>>> +//                       scope."
>>>> +//     },
>>>> +//     "endLine": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Optional end line of the range covered by this scope."
>>>> +//     },
>>>> +//     "endColumn": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Optional end column of the range covered by this
>>>> +//                       scope."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "name", "variablesReference", "expensive" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateScope(const llvm::StringRef name,
>>>> +                              int64_t variablesReference,
>>>> +                              int64_t namedVariables, bool expensive) {
>>>> +  llvm::json::Object object;
>>>> +  object.try_emplace("name", name.str());
>>>> +  object.try_emplace("variablesReference", variablesReference);
>>>> +  object.try_emplace("expensive", expensive);
>>>> +  object.try_emplace("namedVariables", namedVariables);
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "Breakpoint": {
>>>> +//   "type": "object",
>>>> +//   "description": "Information about a Breakpoint created in setBreakpoints
>>>> +//                   or setFunctionBreakpoints.",
>>>> +//   "properties": {
>>>> +//     "id": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional unique identifier for the breakpoint."
>>>> +//     },
>>>> +//     "verified": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "If true breakpoint could be set (but not necessarily
>>>> +//                       at the desired location)."
>>>> +//     },
>>>> +//     "message": {
>>>> +//       "type": "string",
>>>> +//       "description": "An optional message about the state of the breakpoint.
>>>> +//                       This is shown to the user and can be used to explain
>>>> +//                       why a breakpoint could not be verified."
>>>> +//     },
>>>> +//     "source": {
>>>> +//       "$ref": "#/definitions/Source",
>>>> +//       "description": "The source where the breakpoint is located."
>>>> +//     },
>>>> +//     "line": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The start line of the actual range covered by the
>>>> +//                       breakpoint."
>>>> +//     },
>>>> +//     "column": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional start column of the actual range covered
>>>> +//                       by the breakpoint."
>>>> +//     },
>>>> +//     "endLine": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional end line of the actual range covered by
>>>> +//                       the breakpoint."
>>>> +//     },
>>>> +//     "endColumn": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional end column of the actual range covered by
>>>> +//                       the breakpoint. If no end line is given, then the end
>>>> +//                       column is assumed to be in the start line."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "verified" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc) {
>>>> +  // Each breakpoint location is treated as a separate breakpoint for VS code.
>>>> +  // They don't have the notion of a single breakpoint with multiple locations.
>>>> +  llvm::json::Object object;
>>>> +  if (!bp_loc.IsValid())
>>>> +    return llvm::json::Value(std::move(object));
>>>> +
>>>> +  object.try_emplace("verified", true);
>>>> +  const auto bp_id = bp_loc.GetBreakpoint().GetID();
>>>> +  const auto vs_id = (int64_t)(((int64_t)bp_id << 32) | bp_loc.GetID());
>>>> +  object.try_emplace("id", vs_id);
>>>> +  auto bp_addr = bp_loc.GetAddress();
>>>> +  if (bp_addr.IsValid()) {
>>>> +    auto line_entry = bp_addr.GetLineEntry();
>>>> +    const auto line = line_entry.GetLine();
>>>> +    if (line != UINT32_MAX)
>>>> +      object.try_emplace("line", line);
>>>> +    object.try_emplace("source", CreateSource(line_entry));
>>>> +  }
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints) {
>>>> +  if (!bp.IsValid())
>>>> +    return;
>>>> +  const auto num_locations = bp.GetNumLocations();
>>>> +  if (num_locations == 0)
>>>> +    return;
>>>> +  for (size_t i = 0; i < num_locations; ++i) {
>>>> +    auto bp_loc = bp.GetLocationAtIndex(i);
>>>> +    breakpoints.emplace_back(CreateBreakpoint(bp_loc));
>>>> +  }
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "Event": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Server-initiated event.",
>>>> +//     "properties": {
>>>> +//       "type": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "event" ]
>>>> +//       },
>>>> +//       "event": {
>>>> +//         "type": "string",
>>>> +//         "description": "Type of event."
>>>> +//       },
>>>> +//       "body": {
>>>> +//         "type": [ "array", "boolean", "integer", "null", "number" ,
>>>> +//                   "object", "string" ],
>>>> +//         "description": "Event-specific information."
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "type", "event" ]
>>>> +//   }]
>>>> +// },
>>>> +// "ProtocolMessage": {
>>>> +//   "type": "object",
>>>> +//   "description": "Base class of requests, responses, and events.",
>>>> +//   "properties": {
>>>> +//         "seq": {
>>>> +//           "type": "integer",
>>>> +//           "description": "Sequence number."
>>>> +//         },
>>>> +//         "type": {
>>>> +//           "type": "string",
>>>> +//           "description": "Message type.",
>>>> +//           "_enum": [ "request", "response", "event" ]
>>>> +//         }
>>>> +//   },
>>>> +//   "required": [ "seq", "type" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Object CreateEvent(const llvm::StringRef event_name) {
>>>> +  llvm::json::Object event;
>>>> +  event.try_emplace("seq", 0);
>>>> +  event.try_emplace("type", "event");
>>>> +  event.try_emplace("event", event_name);
>>>> +  return event;
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "ExceptionBreakpointsFilter": {
>>>> +//   "type": "object",
>>>> +//   "description": "An ExceptionBreakpointsFilter is shown in the UI as an
>>>> +//                   option for configuring how exceptions are dealt with.",
>>>> +//   "properties": {
>>>> +//     "filter": {
>>>> +//       "type": "string",
>>>> +//       "description": "The internal ID of the filter. This value is passed
>>>> +//                       to the setExceptionBreakpoints request."
>>>> +//     },
>>>> +//     "label": {
>>>> +//       "type": "string",
>>>> +//       "description": "The name of the filter. This will be shown in the UI."
>>>> +//     },
>>>> +//     "default": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "Initial value of the filter. If not specified a value
>>>> +//                       'false' is assumed."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "filter", "label" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value
>>>> +CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) {
>>>> +  llvm::json::Object object;
>>>> +  object.try_emplace("filter", bp.filter);
>>>> +  object.try_emplace("label", bp.label);
>>>> +  object.try_emplace("default", bp.default_value);
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "Source": {
>>>> +//   "type": "object",
>>>> +//   "description": "A Source is a descriptor for source code. It is returned
>>>> +//                   from the debug adapter as part of a StackFrame and it is
>>>> +//                   used by clients when specifying breakpoints.",
>>>> +//   "properties": {
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "The short name of the source. Every source returned
>>>> +//                       from the debug adapter has a name. When sending a
>>>> +//                       source to the debug adapter this name is optional."
>>>> +//     },
>>>> +//     "path": {
>>>> +//       "type": "string",
>>>> +//       "description": "The path of the source to be shown in the UI. It is
>>>> +//                       only used to locate and load the content of the
>>>> +//                       source if no sourceReference is specified (or its
>>>> +//                       value is 0)."
>>>> +//     },
>>>> +//     "sourceReference": {
>>>> +//       "type": "number",
>>>> +//       "description": "If sourceReference > 0 the contents of the source must
>>>> +//                       be retrieved through the SourceRequest (even if a path
>>>> +//                       is specified). A sourceReference is only valid for a
>>>> +//                       session, so it must not be used to persist a source."
>>>> +//     },
>>>> +//     "presentationHint": {
>>>> +//       "type": "string",
>>>> +//       "description": "An optional hint for how to present the source in the
>>>> +//                       UI. A value of 'deemphasize' can be used to indicate
>>>> +//                       that the source is not available or that it is
>>>> +//                       skipped on stepping.",
>>>> +//       "enum": [ "normal", "emphasize", "deemphasize" ]
>>>> +//     },
>>>> +//     "origin": {
>>>> +//       "type": "string",
>>>> +//       "description": "The (optional) origin of this source: possible values
>>>> +//                       'internal module', 'inlined content from source map',
>>>> +//                       etc."
>>>> +//     },
>>>> +//     "sources": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "$ref": "#/definitions/Source"
>>>> +//       },
>>>> +//       "description": "An optional list of sources that are related to this
>>>> +//                       source. These may be the source that generated this
>>>> +//                       source."
>>>> +//     },
>>>> +//     "adapterData": {
>>>> +//       "type":["array","boolean","integer","null","number","object","string"],
>>>> +//       "description": "Optional data that a debug adapter might want to loop
>>>> +//                       through the client. The client should leave the data
>>>> +//                       intact and persist it across sessions. The client
>>>> +//                       should not interpret the data."
>>>> +//     },
>>>> +//     "checksums": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "$ref": "#/definitions/Checksum"
>>>> +//       },
>>>> +//       "description": "The checksums associated with this file."
>>>> +//     }
>>>> +//   }
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry) {
>>>> +  llvm::json::Object object;
>>>> +  lldb::SBFileSpec file = line_entry.GetFileSpec();
>>>> +  if (file.IsValid()) {
>>>> +    const char *name = file.GetFilename();
>>>> +    if (name)
>>>> +      object.try_emplace("name", name);
>>>> +    char path[PATH_MAX] = "";
>>>> +    file.GetPath(path, sizeof(path));
>>>> +    if (path[0]) {
>>>> +      object.try_emplace("path", std::string(path));
>>>> +    }
>>>> +  }
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line) {
>>>> +  disasm_line = 0;
>>>> +  auto line_entry = frame.GetLineEntry();
>>>> +  if (line_entry.GetFileSpec().IsValid())
>>>> +    return CreateSource(line_entry);
>>>> +
>>>> +  llvm::json::Object object;
>>>> +  const auto pc = frame.GetPC();
>>>> +
>>>> +  lldb::SBInstructionList insts;
>>>> +  lldb::SBFunction function = frame.GetFunction();
>>>> +  lldb::addr_t low_pc = LLDB_INVALID_ADDRESS;
>>>> +  if (function.IsValid()) {
>>>> +    low_pc = function.GetStartAddress().GetLoadAddress(g_vsc.target);
>>>> +    auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc);
>>>> +    if (addr_srcref != g_vsc.addr_to_source_ref.end()) {
>>>> +      // We have this disassembly cached already, return the existing
>>>> +      // sourceReference
>>>> +      object.try_emplace("sourceReference", addr_srcref->second);
>>>> +      disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc);
>>>> +    } else {
>>>> +      insts = function.GetInstructions(g_vsc.target);
>>>> +    }
>>>> +  } else {
>>>> +    lldb::SBSymbol symbol = frame.GetSymbol();
>>>> +    if (symbol.IsValid()) {
>>>> +      low_pc = symbol.GetStartAddress().GetLoadAddress(g_vsc.target);
>>>> +      auto addr_srcref = g_vsc.addr_to_source_ref.find(low_pc);
>>>> +      if (addr_srcref != g_vsc.addr_to_source_ref.end()) {
>>>> +        // We have this disassembly cached already, return the existing
>>>> +        // sourceReference
>>>> +        object.try_emplace("sourceReference", addr_srcref->second);
>>>> +        disasm_line = g_vsc.GetLineForPC(addr_srcref->second, pc);
>>>> +      } else {
>>>> +        insts = symbol.GetInstructions(g_vsc.target);
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +  const auto num_insts = insts.GetSize();
>>>> +  if (low_pc != LLDB_INVALID_ADDRESS && num_insts > 0) {
>>>> +    object.try_emplace("name", frame.GetFunctionName());
>>>> +    SourceReference source;
>>>> +    llvm::raw_string_ostream src_strm(source.content);
>>>> +    std::string line;
>>>> +    for (size_t i = 0; i < num_insts; ++i) {
>>>> +      lldb::SBInstruction inst = insts.GetInstructionAtIndex(i);
>>>> +      const auto inst_addr = inst.GetAddress().GetLoadAddress(g_vsc.target);
>>>> +      const char *m = inst.GetMnemonic(g_vsc.target);
>>>> +      const char *o = inst.GetOperands(g_vsc.target);
>>>> +      const char *c = inst.GetComment(g_vsc.target);
>>>> +      if (pc == inst_addr)
>>>> +        disasm_line = i + 1;
>>>> +      const auto inst_offset = inst_addr - low_pc;
>>>> +      int spaces = 0;
>>>> +      if (inst_offset < 10)
>>>> +        spaces = 3;
>>>> +      else if (inst_offset < 100)
>>>> +        spaces = 2;
>>>> +      else if (inst_offset < 1000)
>>>> +        spaces = 1;
>>>> +      line.clear();
>>>> +      llvm::raw_string_ostream line_strm(line);
>>>> +      line_strm << llvm::formatv("{0:X+}: <{1}> {2} {3,12} {4}", inst_addr,
>>>> +                                 inst_offset, llvm::fmt_repeat(' ', spaces),
>>>> +                                 m, o);
>>>> +      const uint32_t comment_row = 60;
>>>> +      // If there is a comment append it starting at column 60
>>>> +      if (c && c[0]) {
>>>> +        if (line.size() < comment_row)
>>>> +          line_strm.indent(comment_row - line_strm.str().size());
>>>> +        line_strm << " # " << c;
>>>> +      }
>>>> +      src_strm << line_strm.str() << "\n";
>>>> +      source.addr_to_line[inst_addr] = i + 1;
>>>> +    }
>>>> +    // Flush the source stream
>>>> +    src_strm.str();
>>>> +    auto sourceReference = VSCode::GetNextSourceReference();
>>>> +    g_vsc.source_map[sourceReference] = std::move(source);
>>>> +    g_vsc.addr_to_source_ref[low_pc] = sourceReference;
>>>> +    object.try_emplace("sourceReference", sourceReference);
>>>> +  }
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "StackFrame": {
>>>> +//   "type": "object",
>>>> +//   "description": "A Stackframe contains the source location.",
>>>> +//   "properties": {
>>>> +//     "id": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An identifier for the stack frame. It must be unique
>>>> +//                       across all threads. This id can be used to retrieve
>>>> +//                       the scopes of the frame with the 'scopesRequest' or
>>>> +//                       to restart the execution of a stackframe."
>>>> +//     },
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "The name of the stack frame, typically a method name."
>>>> +//     },
>>>> +//     "source": {
>>>> +//       "$ref": "#/definitions/Source",
>>>> +//       "description": "The optional source of the frame."
>>>> +//     },
>>>> +//     "line": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The line within the file of the frame. If source is
>>>> +//                       null or doesn't exist, line is 0 and must be ignored."
>>>> +//     },
>>>> +//     "column": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The column within the line. If source is null or
>>>> +//                       doesn't exist, column is 0 and must be ignored."
>>>> +//     },
>>>> +//     "endLine": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional end line of the range covered by the
>>>> +//                       stack frame."
>>>> +//     },
>>>> +//     "endColumn": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional end column of the range covered by the
>>>> +//                       stack frame."
>>>> +//     },
>>>> +//     "moduleId": {
>>>> +//       "type": ["integer", "string"],
>>>> +//       "description": "The module associated with this frame, if any."
>>>> +//     },
>>>> +//     "presentationHint": {
>>>> +//       "type": "string",
>>>> +//       "enum": [ "normal", "label", "subtle" ],
>>>> +//       "description": "An optional hint for how to present this frame in
>>>> +//                       the UI. A value of 'label' can be used to indicate
>>>> +//                       that the frame is an artificial frame that is used
>>>> +//                       as a visual label or separator. A value of 'subtle'
>>>> +//                       can be used to change the appearance of a frame in
>>>> +//                       a 'subtle' way."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "id", "name", "line", "column" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateStackFrame(lldb::SBFrame &frame) {
>>>> +  llvm::json::Object object;
>>>> +  int64_t frame_id = MakeVSCodeFrameID(frame);
>>>> +  object.try_emplace("id", frame_id);
>>>> +  object.try_emplace("name", frame.GetFunctionName());
>>>> +  int64_t disasm_line = 0;
>>>> +  object.try_emplace("source", CreateSource(frame, disasm_line));
>>>> +
>>>> +  auto line_entry = frame.GetLineEntry();
>>>> +  if (disasm_line > 0) {
>>>> +    object.try_emplace("line", disasm_line);
>>>> +  } else {
>>>> +    auto line = line_entry.GetLine();
>>>> +    if (line == UINT32_MAX)
>>>> +      line = 0;
>>>> +    object.try_emplace("line", line);
>>>> +  }
>>>> +  object.try_emplace("column", line_entry.GetColumn());
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "Thread": {
>>>> +//   "type": "object",
>>>> +//   "description": "A Thread",
>>>> +//   "properties": {
>>>> +//     "id": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Unique identifier for the thread."
>>>> +//     },
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "A name of the thread."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "id", "name" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateThread(lldb::SBThread &thread) {
>>>> +  llvm::json::Object object;
>>>> +  object.try_emplace("id", (int64_t)thread.GetThreadID());
>>>> +  char thread_str[64];
>>>> +  snprintf(thread_str, sizeof(thread_str), "Thread #%u", thread.GetIndexID());
>>>> +  const char *name = thread.GetName();
>>>> +  if (name) {
>>>> +    std::string thread_with_name(thread_str);
>>>> +    thread_with_name += ' ';
>>>> +    thread_with_name += name;
>>>> +    object.try_emplace("name", thread_with_name);
>>>> +  } else {
>>>> +    object.try_emplace("name", std::string(thread_str));
>>>> +  }
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "StoppedEvent": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Event" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Event message for 'stopped' event type. The event
>>>> +//                     indicates that the execution of the debuggee has stopped
>>>> +//                     due to some condition. This can be caused by a break
>>>> +//                     point previously set, a stepping action has completed,
>>>> +//                     by executing a debugger statement etc.",
>>>> +//     "properties": {
>>>> +//       "event": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "stopped" ]
>>>> +//       },
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "reason": {
>>>> +//             "type": "string",
>>>> +//             "description": "The reason for the event. For backward
>>>> +//                             compatibility this string is shown in the UI if
>>>> +//                             the 'description' attribute is missing (but it
>>>> +//                             must not be translated).",
>>>> +//             "_enum": [ "step", "breakpoint", "exception", "pause", "entry" ]
>>>> +//           },
>>>> +//           "description": {
>>>> +//             "type": "string",
>>>> +//             "description": "The full reason for the event, e.g. 'Paused
>>>> +//                             on exception'. This string is shown in the UI
>>>> +//                             as is."
>>>> +//           },
>>>> +//           "threadId": {
>>>> +//             "type": "integer",
>>>> +//             "description": "The thread which was stopped."
>>>> +//           },
>>>> +//           "text": {
>>>> +//             "type": "string",
>>>> +//             "description": "Additional information. E.g. if reason is
>>>> +//                             'exception', text contains the exception name.
>>>> +//                             This string is shown in the UI."
>>>> +//           },
>>>> +//           "allThreadsStopped": {
>>>> +//             "type": "boolean",
>>>> +//             "description": "If allThreadsStopped is true, a debug adapter
>>>> +//                             can announce that all threads have stopped.
>>>> +//                             The client should use this information to
>>>> +//                             enable that all threads can be expanded to
>>>> +//                             access their stacktraces. If the attribute
>>>> +//                             is missing or false, only the thread with the
>>>> +//                             given threadId can be expanded."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "reason" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "event", "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
>>>> +                                      uint32_t stop_id) {
>>>> +  llvm::json::Object event(CreateEvent("stopped"));
>>>> +  llvm::json::Object body;
>>>> +  switch (thread.GetStopReason()) {
>>>> +  case lldb::eStopReasonTrace:
>>>> +  case lldb::eStopReasonPlanComplete:
>>>> +    body.try_emplace("reason", "step");
>>>> +    break;
>>>> +  case lldb::eStopReasonBreakpoint: {
>>>> +    ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
>>>> +    if (exc_bp) {
>>>> +      body.try_emplace("reason", "exception");
>>>> +      body.try_emplace("description", exc_bp->label);
>>>> +    } else {
>>>> +      body.try_emplace("reason", "breakpoint");
>>>> +    }
>>>> +  } break;
>>>> +  case lldb::eStopReasonWatchpoint:
>>>> +  case lldb::eStopReasonInstrumentation:
>>>> +    body.try_emplace("reason", "breakpoint");
>>>> +    break;
>>>> +  case lldb::eStopReasonSignal:
>>>> +    body.try_emplace("reason", "exception");
>>>> +    break;
>>>> +  case lldb::eStopReasonException:
>>>> +    body.try_emplace("reason", "exception");
>>>> +    break;
>>>> +  case lldb::eStopReasonExec:
>>>> +    body.try_emplace("reason", "entry");
>>>> +    break;
>>>> +  case lldb::eStopReasonThreadExiting:
>>>> +  case lldb::eStopReasonInvalid:
>>>> +  case lldb::eStopReasonNone:
>>>> +    break;
>>>> +  }
>>>> +  if (stop_id == 0)
>>>> +    body.try_emplace("reason", "entry");
>>>> +  const lldb::tid_t tid = thread.GetThreadID();
>>>> +  body.try_emplace("threadId", (int64_t)tid);
>>>> +  // If no description has been set, then set it to the default thread stopped
>>>> +  // description. If we have breakpoints that get hit and shouldn't be reported
>>>> +  // as breakpoints, then they will set the description above.
>>>> +  if (ObjectContainsKey(body, "description")) {
>>>> +    char description[1024];
>>>> +    if (thread.GetStopDescription(description, sizeof(description))) {
>>>> +      body.try_emplace("description", std::string(description));
>>>> +    }
>>>> +  }
>>>> +  if (tid == g_vsc.focus_tid) {
>>>> +    body.try_emplace("threadCausedFocus", true);
>>>> +  }
>>>> +  body.try_emplace("preserveFocusHint", tid != g_vsc.focus_tid);
>>>> +  body.try_emplace("allThreadsStopped", true);
>>>> +  event.try_emplace("body", std::move(body));
>>>> +  return llvm::json::Value(std::move(event));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "Variable": {
>>>> +//   "type": "object",
>>>> +//   "description": "A Variable is a name/value pair. Optionally a variable
>>>> +//                   can have a 'type' that is shown if space permits or when
>>>> +//                   hovering over the variable's name. An optional 'kind' is
>>>> +//                   used to render additional properties of the variable,
>>>> +//                   e.g. different icons can be used to indicate that a
>>>> +//                   variable is public or private. If the value is
>>>> +//                   structured (has children), a handle is provided to
>>>> +//                   retrieve the children with the VariablesRequest. If
>>>> +//                   the number of named or indexed children is large, the
>>>> +//                   numbers should be returned via the optional
>>>> +//                   'namedVariables' and 'indexedVariables' attributes. The
>>>> +//                   client can use this optional information to present the
>>>> +//                   children in a paged UI and fetch them in chunks.",
>>>> +//   "properties": {
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "The variable's name."
>>>> +//     },
>>>> +//     "value": {
>>>> +//       "type": "string",
>>>> +//       "description": "The variable's value. This can be a multi-line text,
>>>> +//                       e.g. for a function the body of a function."
>>>> +//     },
>>>> +//     "type": {
>>>> +//       "type": "string",
>>>> +//       "description": "The type of the variable's value. Typically shown in
>>>> +//                       the UI when hovering over the value."
>>>> +//     },
>>>> +//     "presentationHint": {
>>>> +//       "$ref": "#/definitions/VariablePresentationHint",
>>>> +//       "description": "Properties of a variable that can be used to determine
>>>> +//                       how to render the variable in the UI."
>>>> +//     },
>>>> +//     "evaluateName": {
>>>> +//       "type": "string",
>>>> +//       "description": "Optional evaluatable name of this variable which can
>>>> +//                       be passed to the 'EvaluateRequest' to fetch the
>>>> +//                       variable's value."
>>>> +//     },
>>>> +//     "variablesReference": {
>>>> +//       "type": "integer",
>>>> +//       "description": "If variablesReference is > 0, the variable is
>>>> +//                       structured and its children can be retrieved by
>>>> +//                       passing variablesReference to the VariablesRequest."
>>>> +//     },
>>>> +//     "namedVariables": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The number of named child variables. The client can
>>>> +//                       use this optional information to present the children
>>>> +//                       in a paged UI and fetch them in chunks."
>>>> +//     },
>>>> +//     "indexedVariables": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The number of indexed child variables. The client
>>>> +//                       can use this optional information to present the
>>>> +//                       children in a paged UI and fetch them in chunks."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "name", "value", "variablesReference" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
>>>> +                                 int64_t varID, bool format_hex) {
>>>> +  llvm::json::Object object;
>>>> +  auto name = v.GetName();
>>>> +  object.try_emplace("name", name ? name : "<null>");
>>>> +  if (format_hex)
>>>> +    v.SetFormat(lldb::eFormatHex);
>>>> +  SetValueForKey(v, object, "value");
>>>> +  auto type_cstr = v.GetType().GetDisplayTypeName();
>>>> +  object.try_emplace("type", type_cstr ? type_cstr : NO_TYPENAME);
>>>> +  if (varID != INT64_MAX)
>>>> +    object.try_emplace("id", varID);
>>>> +  if (v.MightHaveChildren())
>>>> +    object.try_emplace("variablesReference", variablesReference);
>>>> +  else
>>>> +    object.try_emplace("variablesReference", (int64_t)0);
>>>> +  lldb::SBStream evaluateStream;
>>>> +  v.GetExpressionPath(evaluateStream);
>>>> +  const char *evaluateName = evaluateStream.GetData();
>>>> +  if (evaluateName && evaluateName[0])
>>>> +    object.try_emplace("evaluateName", std::string(evaluateName));
>>>> +  return llvm::json::Value(std::move(object));
>>>> +}
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/JSONUtils.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/JSONUtils.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/JSONUtils.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/JSONUtils.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/JSONUtils.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,421 @@
>>>> +//===-- JSONUtils.h ---------------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_JSONUTILS_H_
>>>> +#define LLDBVSCODE_JSONUTILS_H_
>>>> +
>>>> +#include <stdint.h>
>>>> +#include "llvm/ADT/StringRef.h"
>>>> +#include "llvm/Support/JSON.h"
>>>> +#include "VSCodeForward.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +  
>>>> +//------------------------------------------------------------------
>>>> +/// Extract simple values as a string.
>>>> +///
>>>> +/// @param[in] value
>>>> +///     A JSON value to extract the string from.
>>>> +///
>>>> +/// @return
>>>> +///     A llvm::StringRef that contains the string value, or an empty
>>>> +///     string if \a value isn't a string.
>>>> +//------------------------------------------------------------------
>>>> +llvm::StringRef GetAsString(const llvm::json::Value &value);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Extract the string value for the specified key from the
>>>> +/// specified object.
>>>> +///
>>>> +/// @param[in] obj
>>>> +///     A JSON object that we will attempt to extract the value from
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key to use when extracting the value
>>>> +///
>>>> +/// @return
>>>> +///     A llvm::StringRef that contains the string value for the
>>>> +///     specified \a key, or an empty string if there is no key that
>>>> +///     matches or if the value is not a string.
>>>> +//------------------------------------------------------------------
>>>> +llvm::StringRef GetString(const llvm::json::Object &obj, llvm::StringRef key);
>>>> +llvm::StringRef GetString(const llvm::json::Object *obj, llvm::StringRef key);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Extract the unsigned integer value for the specified key from
>>>> +/// the specified object.
>>>> +///
>>>> +/// @param[in] obj
>>>> +///     A JSON object that we will attempt to extract the value from
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key to use when extracting the value
>>>> +///
>>>> +/// @return
>>>> +///     The unsigned integer value for the specified \a key, or
>>>> +///     \a fail_value  if there is no key that matches or if the
>>>> +///     value is not an integer.
>>>> +//------------------------------------------------------------------
>>>> +uint64_t GetUnsigned(const llvm::json::Object &obj, llvm::StringRef key,
>>>> +                     uint64_t fail_value);
>>>> +uint64_t GetUnsigned(const llvm::json::Object *obj, llvm::StringRef key,
>>>> +                     uint64_t fail_value);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Extract the boolean value for the specified key from the
>>>> +/// specified object.
>>>> +///
>>>> +/// @param[in] obj
>>>> +///     A JSON object that we will attempt to extract the value from
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key to use when extracting the value
>>>> +///
>>>> +/// @return
>>>> +///     The boolean value for the specified \a key, or \a fail_value
>>>> +///     if there is no key that matches or if the value is not a
>>>> +///     boolean value of an integer.
>>>> +//------------------------------------------------------------------
>>>> +bool GetBoolean(const llvm::json::Object &obj, llvm::StringRef key,
>>>> +                bool fail_value);
>>>> +bool GetBoolean(const llvm::json::Object *obj, llvm::StringRef key,
>>>> +                bool fail_value);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Extract the signed integer for the specified key from the
>>>> +/// specified object.
>>>> +///
>>>> +/// @param[in] obj
>>>> +///     A JSON object that we will attempt to extract the value from
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key to use when extracting the value
>>>> +///
>>>> +/// @return
>>>> +///     The signed integer value for the specified \a key, or
>>>> +///     \a fail_value if there is no key that matches or if the
>>>> +///     value is not an integer.
>>>> +//------------------------------------------------------------------
>>>> +int64_t GetSigned(const llvm::json::Object &obj, llvm::StringRef key,
>>>> +                  int64_t fail_value);
>>>> +int64_t GetSigned(const llvm::json::Object *obj, llvm::StringRef key,
>>>> +                  int64_t fail_value);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Check if the specified key exists in the specified object.
>>>> +///
>>>> +/// @param[in] obj
>>>> +///     A JSON object that we will attempt to extract the value from
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key to check for
>>>> +///
>>>> +/// @return
>>>> +///     \b True if the key exists in the \a obj, \b False otherwise.
>>>> +//------------------------------------------------------------------
>>>> +bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Extract an array of strings for the specified key from an object.
>>>> +///
>>>> +/// String values in the array will be extracted without any quotes
>>>> +/// around them. Numbers and Booleans will be converted into
>>>> +/// strings. Any NULL, array or objects values in the array will be
>>>> +/// ignored.
>>>> +///
>>>> +/// @param[in] obj
>>>> +///     A JSON object that we will attempt to extract the array from
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key to use when extracting the value
>>>> +///
>>>> +/// @return
>>>> +///     An array of string values for the specified \a key, or
>>>> +///     \a fail_value if there is no key that matches or if the
>>>> +///     value is not an array or all items in the array are not
>>>> +///     strings, numbers or booleans.
>>>> +//------------------------------------------------------------------
>>>> +std::vector<std::string> GetStrings(const llvm::json::Object *obj,
>>>> +                                    llvm::StringRef key);
>>>> +
>>>> +//------------------------------------------------------------------
>>>> +/// Fill a response object given the request object.
>>>> +///
>>>> +/// The \a response object will get its "type" set to "response",
>>>> +/// the "seq" set to zero, "response_seq" set to the "seq" value from
>>>> +/// \a request, "command" set to the "command" from \a request,
>>>> +/// and "success" set to true.
>>>> +///
>>>> +/// @param[in] request
>>>> +///     The request object received from a call to VSCode::ReadJSON().
>>>> +///
>>>> +/// @param[in,out] response
>>>> +///     An empty llvm::json::Object object that will be filled
>>>> +///     in as noted in description.
>>>> +//------------------------------------------------------------------
>>>> +void FillResponse(const llvm::json::Object &request,
>>>> +                  llvm::json::Object &response);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Emplace the string value from an SBValue into the supplied object
>>>> +/// using \a key as the key that will contain the value.
>>>> +///
>>>> +/// The value is what we will display in VS Code. Some SBValue objects
>>>> +/// can have a value and/or a summary. If a value has both, we
>>>> +/// combine the value and the summary into one string. If we only have a
>>>> +/// value or summary, then that is considered the value. If there is
>>>> +/// no value and no summary then the value is the type name followed by
>>>> +/// the address of the type if it has an address.
>>>> +///
>>>> +///
>>>> +/// @param[in] v
>>>> +///     A lldb::SBValue object to extract the string value from
>>>> +///
>>>> +///
>>>> +/// @param[in] object
>>>> +///     The object to place the value object into
>>>> +///
>>>> +///
>>>> +/// @param[in] key
>>>> +///     The key name to use when inserting the value object we create
>>>> +//----------------------------------------------------------------------
>>>> +void SetValueForKey(lldb::SBValue &v, llvm::json::Object &object,
>>>> +                    llvm::StringRef key);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Converts \a bp to a JSON value and appends all locations to the
>>>> +/// \a breakpoints array.
>>>> +///
>>>> +/// @param[in] bp
>>>> +///     A LLDB breakpoint object which will get all locations extracted
>>>> +///     and converted into a JSON objects in the \a breakpoints array
>>>> +///
>>>> +/// @param[in] breakpoints
>>>> +///     A JSON array that will get a llvm::json::Value for \a bp
>>>> +///     appended to it.
>>>> +//----------------------------------------------------------------------
>>>> +void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Converts breakpoint location to a Visual Studio Code "Breakpoint"
>>>> +/// JSON object and appends it to the \a breakpoints array.
>>>> +///
>>>> +/// @param[in] bp_loc
>>>> +///     A LLDB breakpoint location object to convert into a JSON value
>>>> +///
>>>> +/// @return
>>>> +///     A "Breakpoint" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "Event" JSON object using \a event_name as the event name
>>>> +///
>>>> +/// @param[in] event_name
>>>> +///     The string value to use for the "event" key in the JSON object.
>>>> +///
>>>> +/// @return
>>>> +///     A "Event" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Object CreateEvent(const llvm::StringRef event_name);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "ExceptionBreakpointsFilter" JSON object as described in
>>>> +/// the Visual Studio Code debug adaptor definition.
>>>> +///
>>>> +/// @param[in] bp
>>>> +///     The exception breakppoint object to use
>>>> +///
>>>> +/// @return
>>>> +///     A "ExceptionBreakpointsFilter" JSON object with that follows
>>>> +///     the formal JSON definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value
>>>> +CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "Scope" JSON object as described in the Visual Studio Code
>>>> +/// debug adaptor definition.
>>>> +///
>>>> +/// @param[in] name
>>>> +///     The value to place into the "name" key
>>>> +//
>>>> +/// @param[in] variablesReference
>>>> +///     The value to place into the "variablesReference" key
>>>> +//
>>>> +/// @param[in] namedVariables
>>>> +///     The value to place into the "namedVariables" key
>>>> +//
>>>> +/// @param[in] expensive
>>>> +///     The value to place into the "expensive" key
>>>> +///
>>>> +/// @return
>>>> +///     A "Scope" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateScope(const llvm::StringRef name,
>>>> +                              int64_t variablesReference,
>>>> +                              int64_t namedVariables, bool expensive);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "Source" JSON object as described in the Visual Studio Code
>>>> +/// debug adaptor definition.
>>>> +///
>>>> +/// @param[in] line_entry
>>>> +///     The LLDB line table to use when populating out the "Source"
>>>> +///     object
>>>> +///
>>>> +/// @return
>>>> +///     A "Source" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateSource(lldb::SBLineEntry &line_entry);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "Source" object for a given frame.
>>>> +///
>>>> +/// When there is no source file information for a stack frame, we will
>>>> +/// create disassembly for a function and store a permanent
>>>> +/// "sourceReference" that contains the textual disassembly for a
>>>> +/// function along with address to line information. The "Source" object
>>>> +/// that is created will contain a "sourceReference" that the VSCode
>>>> +/// protocol can later fetch as text in order to display disassembly.
>>>> +/// The PC will be extracted from the frame and the disassembly line
>>>> +/// within the source referred to by "sourceReference" will be filled
>>>> +/// in.
>>>> +///
>>>> +/// @param[in] frame
>>>> +///     The LLDB stack frame to use when populating out the "Source"
>>>> +///     object.
>>>> +///
>>>> +/// @param[out] disasm_line
>>>> +///     The line within the "sourceReference" file that the PC from
>>>> +///     \a frame matches.
>>>> +///
>>>> +/// @return
>>>> +///     A "Source" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateSource(lldb::SBFrame &frame, int64_t &disasm_line);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "StackFrame" object for a LLDB frame object.
>>>> +///
>>>> +/// This function will fill in the following keys in the returned
>>>> +/// object:
>>>> +///   "id" - the stack frame ID as an integer
>>>> +///   "name" - the function name as a string
>>>> +///   "source" - source file information as a "Source" VSCode object
>>>> +///   "line" - the source file line number as an integer
>>>> +///   "column" - the source file column number as an integer
>>>> +///
>>>> +/// @param[in] frame
>>>> +///     The LLDB stack frame to use when populating out the "StackFrame"
>>>> +///     object.
>>>> +///
>>>> +/// @return
>>>> +///     A "StackFrame" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateStackFrame(lldb::SBFrame &frame);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "Thread" object for a LLDB thread object.
>>>> +///
>>>> +/// This function will fill in the following keys in the returned
>>>> +/// object:
>>>> +///   "id" - the thread ID as an integer
>>>> +///   "name" - the thread name as a string which combines the LLDB
>>>> +///            thread index ID along with the string name of the thread
>>>> +///            from the OS if it has a name.
>>>> +///
>>>> +/// @param[in] thread
>>>> +///     The LLDB thread to use when populating out the "Thread"
>>>> +///     object.
>>>> +///
>>>> +/// @return
>>>> +///     A "Thread" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateThread(lldb::SBThread &thread);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "StoppedEvent" object for a LLDB thread object.
>>>> +///
>>>> +/// This function will fill in the following keys in the returned
>>>> +/// object's "body" object:
>>>> +///   "reason" - With a valid stop reason enumeration string value
>>>> +///              that Microsoft specifies
>>>> +///   "threadId" - The thread ID as an integer
>>>> +///   "description" - a stop description (like "breakpoint 12.3") as a
>>>> +///                   string
>>>> +///   "preserveFocusHint" - a boolean value that states if this thread
>>>> +///                         should keep the focus in the GUI.
>>>> +///   "allThreadsStopped" - set to True to indicate that all threads
>>>> +///                         stop when any thread stops.
>>>> +///
>>>> +/// @param[in] thread
>>>> +///     The LLDB thread to use when populating out the "StoppedEvent"
>>>> +///     object.
>>>> +///
>>>> +/// @return
>>>> +///     A "StoppedEvent" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, uint32_t stop_id);
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +/// Create a "Variable" object for a LLDB thread object.
>>>> +///
>>>> +/// This function will fill in the following keys in the returned
>>>> +/// object:
>>>> +///   "name" - the name of the variable
>>>> +///   "value" - the value of the variable as a string
>>>> +///   "type" - the typename of the varaible as a string
>>>> +///   "id" - a unique identifier for a value in case there are multiple
>>>> +///          variables with the same name. Other parts of the VSCode
>>>> +///          protocol refer to values by name so this can help
>>>> +///          disambiguate such cases if a IDE passes this "id" value
>>>> +///          back down.
>>>> +///   "variablesReference" - Zero if the variable has no children,
>>>> +///          non-zero integer otherwise which can be used to expand
>>>> +///          the variable.
>>>> +///   "evaluateName" - The name of the variable to use in expressions
>>>> +///                    as a string.
>>>> +///
>>>> +/// @param[in] v
>>>> +///     The LLDB value to use when populating out the "Variable"
>>>> +///     object.
>>>> +///
>>>> +/// @param[in] variablesReference
>>>> +///     The variable reference. Zero if this value isn't structured
>>>> +///     and has no children, non-zero if it does have children and
>>>> +///     might be asked to expand itself.
>>>> +///
>>>> +/// @param[in] varID
>>>> +///     A unique variable indentifier to help in properly identifying
>>>> +///     variables with the same name. This is an extension to the
>>>> +///     VS protocol.
>>>> +///
>>>> +/// @param[in] format_hex
>>>> +///     It set to true the variable will be formatted as hex in
>>>> +///     the "value" key value pair for the value of the variable.
>>>> +///
>>>> +/// @return
>>>> +///     A "Variable" JSON object with that follows the formal JSON
>>>> +///     definition outlined by Microsoft.
>>>> +//----------------------------------------------------------------------
>>>> +llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
>>>> +                                 int64_t varID, bool format_hex);
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/LLDBUtils.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/LLDBUtils.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/LLDBUtils.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/LLDBUtils.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/LLDBUtils.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,73 @@
>>>> +//===-- LLDBUtils.cpp -------------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include "LLDBUtils.h"
>>>> +#include "VSCode.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +void RunLLDBCommands(llvm::StringRef prefix,
>>>> +                     const llvm::ArrayRef<std::string> &commands,
>>>> +                     llvm::raw_ostream &strm) {
>>>> +  if (commands.empty())
>>>> +    return;
>>>> +  lldb::SBCommandInterpreter interp = g_vsc.debugger.GetCommandInterpreter();
>>>> +  if (!prefix.empty())
>>>> +    strm << prefix << "\n";
>>>> +  for (const auto &command : commands) {
>>>> +    lldb::SBCommandReturnObject result;
>>>> +    strm << "(lldb) " << command << "\n";
>>>> +    interp.HandleCommand(command.c_str(), result);
>>>> +    auto output_len = result.GetOutputSize();
>>>> +    if (output_len) {
>>>> +      const char *output = result.GetOutput();
>>>> +      strm << output;
>>>> +    }
>>>> +    auto error_len = result.GetErrorSize();
>>>> +    if (error_len) {
>>>> +      const char *error = result.GetError();
>>>> +      strm << error;
>>>> +    }
>>>> +  }
>>>> +}
>>>> +
>>>> +std::string RunLLDBCommands(llvm::StringRef prefix,
>>>> +                            const llvm::ArrayRef<std::string> &commands) {
>>>> +  std::string s;
>>>> +  llvm::raw_string_ostream strm(s);
>>>> +  RunLLDBCommands(prefix, commands, strm);
>>>> +  strm.flush();
>>>> +  return s;
>>>> +}
>>>> +
>>>> +bool ThreadHasStopReason(lldb::SBThread &thread) {
>>>> +  switch (thread.GetStopReason()) {
>>>> +  case lldb::eStopReasonTrace:
>>>> +  case lldb::eStopReasonPlanComplete:
>>>> +  case lldb::eStopReasonBreakpoint:
>>>> +  case lldb::eStopReasonWatchpoint:
>>>> +  case lldb::eStopReasonInstrumentation:
>>>> +  case lldb::eStopReasonSignal:
>>>> +  case lldb::eStopReasonException:
>>>> +  case lldb::eStopReasonExec:
>>>> +    return true;
>>>> +  case lldb::eStopReasonThreadExiting:
>>>> +  case lldb::eStopReasonInvalid:
>>>> +  case lldb::eStopReasonNone:
>>>> +    break;
>>>> +  }
>>>> +  return false;
>>>> +}
>>>> +
>>>> +int64_t MakeVSCodeFrameID(lldb::SBFrame &frame) {
>>>> +  return (int64_t)frame.GetThread().GetIndexID() << 32 |
>>>> +         (int64_t)frame.GetFrameID();
>>>> +}
>>>> +
>>>> +} // namespace lldb_vscode
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/LLDBUtils.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/LLDBUtils.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/LLDBUtils.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/LLDBUtils.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/LLDBUtils.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,94 @@
>>>> +//===-- LLDBUtils.h ---------------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_LLDBUTILS_H_
>>>> +#define LLDBVSCODE_LLDBUTILS_H_
>>>> +
>>>> +#include "VSCodeForward.h"
>>>> +#include "llvm/ADT/ArrayRef.h"
>>>> +#include "llvm/ADT/StringRef.h"
>>>> +#include "llvm/Support/raw_ostream.h"
>>>> +#include <string>
>>>> +#include <vector>
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +///----------------------------------------------------------------------
>>>> +/// Run a list of LLDB commands in the LLDB command interpreter.
>>>> +///
>>>> +/// All output from every command, including the prompt + the command
>>>> +/// is placed into the "strm" argument.
>>>> +///
>>>> +/// @param[in] prefix
>>>> +///     A string that will be printed into \a strm prior to emitting
>>>> +///     the prmopt + command and command output. Can be NULL.
>>>> +///
>>>> +/// @param[in] commands
>>>> +///     An array of LLDB commands to execute.
>>>> +///
>>>> +/// @param[in] strm
>>>> +///     The stream that will receive the prefix, prompt + command and
>>>> +///     all command output.
>>>> +//----------------------------------------------------------------------
>>>> +void RunLLDBCommands(llvm::StringRef prefix,
>>>> +                     const llvm::ArrayRef<std::string> &commands,
>>>> +                     llvm::raw_ostream &strm);
>>>> +
>>>> +///----------------------------------------------------------------------
>>>> +/// Run a list of LLDB commands in the LLDB command interpreter.
>>>> +///
>>>> +/// All output from every command, including the prompt + the command
>>>> +/// is returned in the std::string return value.
>>>> +///
>>>> +/// @param[in] prefix
>>>> +///     A string that will be printed into \a strm prior to emitting
>>>> +///     the prmopt + command and command output. Can be NULL.
>>>> +///
>>>> +/// @param[in] commands
>>>> +///     An array of LLDB commands to execute.
>>>> +///
>>>> +/// @return
>>>> +///     A std::string that contains the prefix and all commands and
>>>> +///     command output
>>>> +//----------------------------------------------------------------------
>>>> +std::string RunLLDBCommands(llvm::StringRef prefix,
>>>> +                            const llvm::ArrayRef<std::string> &commands);
>>>> +
>>>> +///----------------------------------------------------------------------
>>>> +/// Check if a thread has a stop reason.
>>>> +///
>>>> +/// @param[in] thread
>>>> +///     The LLDB thread object to check
>>>> +///
>>>> +/// @return
>>>> +///     \b True if the thread has a valid stop reason, \b false
>>>> +///     otherwise.
>>>> +//----------------------------------------------------------------------
>>>> +bool ThreadHasStopReason(lldb::SBThread &thread);
>>>> +
>>>> +///----------------------------------------------------------------------
>>>> +/// Given a LLDB frame, make a frame ID that is unique to a specific
>>>> +/// thread and frame.
>>>> +///
>>>> +/// VSCode requires a Stackframe "id" to be unique, so we use the frame
>>>> +/// index in the lower 32 bits and the thread index ID in the upper 32
>>>> +/// bits.
>>>> +///
>>>> +/// @param[in] frame
>>>> +///     The LLDB stack frame object generate the ID for
>>>> +///
>>>> +/// @return
>>>> +///     A unique integer that allows us to easily find the right
>>>> +///     stack frame within a thread on subsequent VS code requests.
>>>> +//----------------------------------------------------------------------
>>>> +int64_t MakeVSCodeFrameID(lldb::SBFrame &frame);
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/README.md
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/README.md?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/README.md?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/README.md (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/README.md Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,194 @@
>>>> +
>>>> +# Table of Contents
>>>> +
>>>> +- [Introduction](#Introduction)
>>>> +- [Intallation](#Intallation Visual Studio Code)
>>>> +- [Configurations](#configurations)
>>>> +	- [Launch Configuration Settings](#launch configuration settings)
>>>> +	- [Attach Configuration Settings](#attach configuration settings)
>>>> +	- [Example configurations](#example configurations)
>>>> +		- [Launching](#launching)
>>>> +		- [Attach to process using process ID](#attach using pid)
>>>> +		- [Attach to process by name](#attach by name)
>>>> +		- [Loading a core file](#loading a core file)
>>>> +
>>>> +# Introduction
>>>> +
>>>> +The `lldb-vscode` tool creates a command line tool that implements the [Visual
>>>> +Studio Code Debug API](https://code.visualstudio.com/docs/extensionAPI/api-debugging <https://code.visualstudio.com/docs/extensionAPI/api-debugging>).
>>>> +It can be installed as an extension for the Visual Studio Code and Nuclide IDE. 
>>>> +The protocol is easy to run remotely and also can allow other tools and IDEs to
>>>> +get a full featured debugger with a well defined protocol. 
>>>> +
>>>> +# Intallation for Visual Studio Code
>>>> +
>>>> +Installing the plug-in involves creating a directory in the `~/.vscode/extensions` folder and copying the package.json file that is in the same directory as this
>>>> +documentation into it, and copying to symlinking a lldb-vscode binary into 
>>>> +the `bin` directory inside the plug-in directory.
>>>> +
>>>> +If you want to make a stand alone plug-in that you can send to others on unix systems:
>>>> +
>>>> +```
>>>> +$ mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
>>>> +$ cp package.json ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0
>>>> +$ cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
>>>> +$ cp /path/to/a/built/lldb-vscode .
>>>> +$ cp /path/to/a/built/liblldb.so .
>>>> +```
>>>> +
>>>> +
>>>> +If you want to make a stand alone plug-in that you can send to others on macOS systems:
>>>> +
>>>> +```
>>>> +$ mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
>>>> +$ cp package.json ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0
>>>> +$ cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
>>>> +$ cp /path/to/a/built/lldb-vscode .
>>>> +$ rsync -av /path/to/a/built/LLDB.framework LLDB.framework
>>>> +```
>>>> +
>>>> +You might need to create additional directories for the `liblldb.so` or `LLDB.framework` inside or next to the `bin` folder depending on how the [rpath](https://en.wikipedia.org/wiki/Rpath <https://en.wikipedia.org/wiki/Rpath>) is set in your `lldb-vscode` binary. By default the `Debug` builds of LLDB usually includes
>>>> +the current executable directory in the rpath, so these steps should work for most people.
>>>> +
>>>> +To create a plug-in that symlinks into your `lldb-vscode` in your build directory:
>>>> +
>>>> +```
>>>> +$ mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
>>>> +$ cp package.json ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0
>>>> +$ cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
>>>> +$ ln -s /path/to/a/built/lldb-vscode
>>>> +```
>>>> +
>>>> +This is handy if you want to debug and develope the `lldb-vscode` executable when adding features or fixing bugs.
>>>> +
>>>> +# Configurations
>>>> +
>>>> +Launching to attaching require you to create a [launch configuration](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations <https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations>). This file
>>>> +defines arguments that get passed to `lldb-vscode` and the configuration settings
>>>> +control how the launch or attach happens.
>>>> +
>>>> +## Launch Configuration Settings
>>>> +
>>>> +When you launch a program with Visual Studio Code you will need to create a [launch.json](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations <https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations>)
>>>> +file that defines how your program will be run. The JSON configuration file can contain the following `lldb-vscode` specific launch key/value pairs:
>>>> +
>>>> +|parameter          |type|req |         |
>>>> +|-------------------|----|:--:|---------|
>>>> +|**name**           |string|Y| A configuration name that will be displayed in the IDE.
>>>> +|**type**           |string|Y| Must be "lldb-vscode".
>>>> +|**request**        |string|Y| Must be "launch".
>>>> +|**program**        |string|Y| Path to the executable to launch.
>>>> +|**args**           |[string]|| An array of command line argument strings to be passed to the program being launched.
>>>> +|**cwd**            |string| | The program working directory.
>>>> +|**env**            |dictionary| | Environment variables to set when launching the program. The format of each environment variable string is "VAR=VALUE" for environment variables with values or just "VAR" for environment variables with no values.
>>>> +|**stopOnEntry**    |boolean| | Whether to stop program immediately after launching.
>>>> +|**initCommands**   |[string]| | LLDB commands executed upon debugger startup prior to creating a the LLDB target. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**preRunCommands** |[string]| | LLDB commands executed just before launching after the LLDB target has been created. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**stopCommands**   |[string]| | LLDB commands executed just after each stop. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**exitCommands**   |[string]| | LLDB commands executed when the program exits. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**sourceMap**      |[string[2]]| | Specify an array of path re-mappings. Each element in the array must be a two element array containing a source and destination pathname.
>>>> +|**debuggerRoot**   | string| |Specify a working directory to use when launching lldb-vscode. If the debug information in your executable contains relative paths, this option can be used so that `lldb-vscode` can find source files and object files that have relative paths.
>>>> +
>>>> +## Attaching Settings
>>>> +
>>>> +When attaching to a process using LLDB you can attach in a few ways
>>>> +
>>>> +1. Attach to an existing process using the process ID
>>>> +2. Attach to an existing process by name
>>>> +3. Attach by name by waiting for the next instance of a process to launch
>>>> +
>>>> +The JSON configuration file can contain the following `lldb-vscode` specific launch key/value pairs:
>>>> +
>>>> +|parameter          |type    |req |         |
>>>> +|-------------------|--------|:--:|---------|
>>>> +|**name**           |string  |Y| A configuration name that will be displayed in the IDE.
>>>> +|**type**           |string  |Y| Must be "lldb-vscode".
>>>> +|**request**        |string  |Y| Must be "attach".
>>>> +|**program**        |string  | | Path to the executable to attach to. This value is optional but can help to resolve breakpoints prior the attaching to the program.
>>>> +|**pid**            |number  | | The process id of the process you wish to attach to. If **pid** is omitted, the debugger will attempt to attach to the program by finding a process whose file name matches the file name from **porgram**. Setting this value to `${command:pickMyProcess}` will allow interactive process selection in the IDE.
>>>> +|**stopOnEntry**    |boolean| | Whether to stop program immediately after launching.
>>>> +|**waitFor**        |boolean | | Wait for the process to launch.
>>>> +|**initCommands**   |[string]| | LLDB commands executed upon debugger startup prior to creating a the LLDB target. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**preRunCommands** |[string]| | LLDB commands executed just before launching after the LLDB target has been created. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**stopCommands**   |[string]| | LLDB commands executed just after each stop. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**exitCommands**   |[string]| | LLDB commands executed when the program exits. Commands and command output will be sent to the debugger console when they are executed.
>>>> +|**attachCommands** |[string]| | LLDB commands that will be executed after **preRunCommands** which take place of the code that normally does the attach. The commands can create a new target and attach or launch it however desired. This allows custom launch and attach configurations. Core files can use `target create --core /path/to/core` to attach to core files.
>>>> +
>>>> +
>>>> +## Example configurations
>>>> +
>>>> +### Launching
>>>> +
>>>> +This will launch `/tmp/a.out` with arguments `one`, `two`, and `three` and
>>>> +adds `FOO=1` and `bar` to the environment:
>>>> +
>>>> +```javascript
>>>> +{
>>>> +  "type": "lldb-vscode",
>>>> +  "request": "launch",
>>>> +  "name": "Debug",
>>>> +  "program": "/tmp/a.out",
>>>> +  "args": [ "one", "two", "three" ],
>>>> +  "env": [ "FOO=1", "BAR" ],
>>>> +}
>>>> +```
>>>> +
>>>> +### Attach using PID
>>>> +
>>>> +This will attach to a process `a.out` whose process ID is 123:
>>>> +
>>>> +```javascript
>>>> +{
>>>> +  "type": "lldb-vscode",
>>>> +  "request": "attach",
>>>> +  "name": "Attach to PID",
>>>> +  "program": "/tmp/a.out",
>>>> +  "pid": 123
>>>> +}
>>>> +```
>>>> +
>>>> +### Attach by Name
>>>> +
>>>> +This will attach to an existing process whose base
>>>> +name matches `a.out`. All we have to do is leave the `pid` value out of the
>>>> +above configuration:
>>>> +
>>>> +```javascript
>>>> +{
>>>> +  "name": "Attach to Name",
>>>> +  "type": "lldb-vscode",
>>>> +  "request": "attach",
>>>> +  "program": "/tmp/a.out",
>>>> +}
>>>> +```
>>>> +
>>>> +If you want to ignore any existing a.out processes and wait for the next instance
>>>> +to be launched you can add the "waitFor" key value pair:
>>>> +
>>>> +```javascript
>>>> +{
>>>> +  "name": "Attach to Name (wait)",
>>>> +  "type": "lldb-vscode",
>>>> +  "request": "attach",
>>>> +  "program": "/tmp/a.out",
>>>> +  "waitFor": true
>>>> +}
>>>> +```
>>>> +
>>>> +This will work as long as the architecture, vendor and OS supports waiting
>>>> +for processes. Currently MacOS is the only platform that supports this.
>>>> +
>>>> +
>>>> +### Loading a Core File
>>>> +
>>>> +Loading a core file can use the `"attach"` request along with the
>>>> +`"attachCommands"` to implement a custom attach:
>>>> +
>>>> +```javascript
>>>> +{
>>>> +  "name": "Attach to Name (wait)",
>>>> +  "type": "lldb-vscode",
>>>> +  "request": "attach",
>>>> +  "attachCommands": ["target create -c /path/to/123.core /path/to/executable"],
>>>> +}
>>>> +```
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/SourceBreakpoint.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/SourceBreakpoint.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/SourceBreakpoint.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/SourceBreakpoint.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/SourceBreakpoint.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,27 @@
>>>> +//===-- SourceBreakpoint.cpp ------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include "SourceBreakpoint.h"
>>>> +#include "VSCode.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +SourceBreakpoint::SourceBreakpoint(const llvm::json::Object &obj)
>>>> +    : BreakpointBase(obj), line(GetUnsigned(obj, "line", 0)),
>>>> +      column(GetUnsigned(obj, "column", 0)) {}
>>>> +
>>>> +void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
>>>> +  bp = g_vsc.target.BreakpointCreateByLocation(source_path.str().c_str(), line);
>>>> +  if (!condition.empty())
>>>> +    SetCondition();
>>>> +  if (!hitCondition.empty())
>>>> +    SetHitCondition();
>>>> +}
>>>> +
>>>> +} // namespace lldb_vscode
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/SourceBreakpoint.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/SourceBreakpoint.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/SourceBreakpoint.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/SourceBreakpoint.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/SourceBreakpoint.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,39 @@
>>>> +//===-- SourceBreakpoint.h --------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_SOURCEBREAKPOINT_H_
>>>> +#define LLDBVSCODE_SOURCEBREAKPOINT_H_
>>>> +
>>>> +#include "llvm/ADT/StringRef.h"
>>>> +#include "BreakpointBase.h"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +struct SourceBreakpoint : public BreakpointBase {
>>>> +
>>>> +  uint32_t line;   ///< The source line of the breakpoint or logpoint
>>>> +  uint32_t column; ///< An optional source column of the breakpoint
>>>> +
>>>> +  SourceBreakpoint() : BreakpointBase(), line(0), column(0) {}
>>>> +  SourceBreakpoint(const llvm::json::Object &obj);
>>>> +
>>>> +  // Set this breakpoint in LLDB as a new breakpoint
>>>> +  void SetBreakpoint(const llvm::StringRef source_path);
>>>> +};
>>>> +
>>>> +inline bool operator<(const SourceBreakpoint &lhs,
>>>> +                      const SourceBreakpoint &rhs) {
>>>> +  if (lhs.line == rhs.line)
>>>> +    return lhs.column < rhs.column;
>>>> +  return lhs.line < rhs.line;
>>>> +}
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/SourceReference.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/SourceReference.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/SourceReference.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/SourceReference.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/SourceReference.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,33 @@
>>>> +//===-- SourceReference.h ---------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_SOURCEREFERENCE_H_
>>>> +#define LLDBVSCODE_SOURCEREFERENCE_H_
>>>> +
>>>> +#include "lldb/lldb-types.h"
>>>> +#include "llvm/ADT/DenseMap.h"
>>>> +#include <string>
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +struct SourceReference {
>>>> +  std::string content;
>>>> +  llvm::DenseMap<lldb::addr_t, int64_t> addr_to_line;
>>>> +
>>>> +  int64_t GetLineForPC(lldb::addr_t pc) const {
>>>> +    auto addr_line = addr_to_line.find(pc);
>>>> +    if (addr_line != addr_to_line.end())
>>>> +      return addr_line->second;
>>>> +    return 0;
>>>> +  }
>>>> +};
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/VSCode.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/VSCode.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/VSCode.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/VSCode.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/VSCode.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,336 @@
>>>> +//===-- VSCode.cpp ----------------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include <stdarg.h>
>>>> +#include <fstream>
>>>> +#include <mutex>
>>>> +
>>>> +#include "VSCode.h"
>>>> +#include "LLDBUtils.h"
>>>> +
>>>> +using namespace lldb_vscode;
>>>> +
>>>> +namespace {
>>>> +  inline bool IsEmptyLine(llvm::StringRef S) {
>>>> +    return S.ltrim().empty();
>>>> +  }
>>>> +} // namespace
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +VSCode g_vsc;
>>>> +
>>>> +VSCode::VSCode()
>>>> +    : in(stdin), out(stdout), launch_info(nullptr), variables(),
>>>> +      broadcaster("lldb-vscode"), num_regs(0), num_locals(0), num_globals(0),
>>>> +      log(), exception_breakpoints(
>>>> +                 {{"cpp_catch", "C++ Catch", lldb::eLanguageTypeC_plus_plus},
>>>> +                  {"cpp_throw", "C++ Throw", lldb::eLanguageTypeC_plus_plus},
>>>> +                  {"objc_catch", "Objective C Catch", lldb::eLanguageTypeObjC},
>>>> +                  {"objc_throw", "Objective C Throw", lldb::eLanguageTypeObjC},
>>>> +                  {"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift},
>>>> +                  {"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}),
>>>> +      focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false),
>>>> +      stop_at_entry(false) {
>>>> +  const char *log_file_path = getenv("LLDBVSCODE_LOG");
>>>> +  if (log_file_path)
>>>> +    log.reset(new std::ofstream(log_file_path));
>>>> +}
>>>> +
>>>> +VSCode::~VSCode() {
>>>> +  CloseInputStream();
>>>> +  CloseOutputStream();
>>>> +}
>>>> +
>>>> +void VSCode::CloseInputStream() {
>>>> +  if (in != stdin) {
>>>> +    fclose(in);
>>>> +    in = nullptr;
>>>> +  }
>>>> +}
>>>> +
>>>> +void VSCode::CloseOutputStream() {
>>>> +  if (out != stdout) {
>>>> +    fclose(out);
>>>> +    out = nullptr;
>>>> +  }
>>>> +}
>>>> +
>>>> +int64_t VSCode::GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const {
>>>> +  auto pos = source_map.find(sourceReference);
>>>> +  if (pos != source_map.end())
>>>> +    return pos->second.GetLineForPC(pc);
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +ExceptionBreakpoint *VSCode::GetExceptionBreakpoint(const std::string &filter) {
>>>> +  for (auto &bp : exception_breakpoints) {
>>>> +    if (bp.filter == filter)
>>>> +      return &bp;
>>>> +  }
>>>> +  return nullptr;
>>>> +}
>>>> +
>>>> +ExceptionBreakpoint *
>>>> +VSCode::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
>>>> +  for (auto &bp : exception_breakpoints) {
>>>> +    if (bp.bp.GetID() == bp_id)
>>>> +      return &bp;
>>>> +  }
>>>> +  return nullptr;
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Send the JSON in "json_str" to the "out" stream. Correctly send the
>>>> +// "Content-Length:" field followed by the length, followed by the raw
>>>> +// JSON bytes.
>>>> +//----------------------------------------------------------------------
>>>> +void VSCode::SendJSON(const std::string &json_str) {
>>>> +  fprintf(out, "Content-Length: %u\r\n\r\n%s", (uint32_t)json_str.size(),
>>>> +          json_str.c_str());
>>>> +  fflush(out);
>>>> +  if (log) {
>>>> +    *log << "<-- " << std::endl
>>>> +         << "Content-Length: " << json_str.size() << "\r\n\r\n"
>>>> +         << json_str << std::endl;
>>>> +  }
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Serialize the JSON value into a string and send the JSON packet to
>>>> +// the "out" stream.
>>>> +//----------------------------------------------------------------------
>>>> +void VSCode::SendJSON(const llvm::json::Value &json) {
>>>> +  std::string s;
>>>> +  llvm::raw_string_ostream strm(s);
>>>> +  strm << json;
>>>> +  static std::mutex mutex;
>>>> +  std::lock_guard<std::mutex> locker(mutex);
>>>> +  SendJSON(strm.str());
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Read a JSON packet from the "in" stream.
>>>> +//----------------------------------------------------------------------
>>>> +std::string VSCode::ReadJSON() {
>>>> +  static std::string header("Content-Length: ");
>>>> +
>>>> +  uint32_t packet_len = 0;
>>>> +  std::string json_str;
>>>> +  char line[1024];
>>>> +
>>>> +  while (fgets(line, sizeof(line), in)) {
>>>> +    if (strncmp(line, header.data(), header.size()) == 0) {
>>>> +      packet_len = atoi(line + header.size());
>>>> +      if (fgets(line, sizeof(line), in)) {
>>>> +        if (!IsEmptyLine(line))
>>>> +          if (log)
>>>> +            *log << "warning: expected empty line but got: \"" << line << "\""
>>>> +                 << std::endl;
>>>> +        break;
>>>> +      }
>>>> +    } else {
>>>> +      if (log)
>>>> +        *log << "warning: expected \"" << header << "\" but got: \"" << line
>>>> +             << "\"" << std::endl;
>>>> +    }
>>>> +  }
>>>> +  // This is followed by two windows newline sequences ("\r\n\r\n") so eat
>>>> +  // two the newline sequences
>>>> +  if (packet_len > 0) {
>>>> +    json_str.resize(packet_len);
>>>> +    auto bytes_read = fread(&json_str[0], 1, packet_len, in);
>>>> +    if (bytes_read < packet_len) {
>>>> +      if (log)
>>>> +        *log << "error: read fewer bytes (" << bytes_read
>>>> +             << ") than requested (" << packet_len << ")" << std::endl;
>>>> +      json_str.erase(bytes_read);
>>>> +    }
>>>> +    if (log) {
>>>> +      *log << "--> " << std::endl;
>>>> +      *log << header << packet_len << "\r\n\r\n" << json_str << std::endl;
>>>> +    }
>>>> +  }
>>>> +  return json_str;
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "OutputEvent": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Event" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Event message for 'output' event type. The event
>>>> +//                     indicates that the target has produced some output.",
>>>> +//     "properties": {
>>>> +//       "event": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "output" ]
>>>> +//       },
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "category": {
>>>> +//             "type": "string",
>>>> +//             "description": "The output category. If not specified,
>>>> +//                             'console' is assumed.",
>>>> +//             "_enum": [ "console", "stdout", "stderr", "telemetry" ]
>>>> +//           },
>>>> +//           "output": {
>>>> +//             "type": "string",
>>>> +//             "description": "The output to report."
>>>> +//           },
>>>> +//           "variablesReference": {
>>>> +//             "type": "number",
>>>> +//             "description": "If an attribute 'variablesReference' exists
>>>> +//                             and its value is > 0, the output contains
>>>> +//                             objects which can be retrieved by passing
>>>> +//                             variablesReference to the VariablesRequest."
>>>> +//           },
>>>> +//           "source": {
>>>> +//             "$ref": "#/definitions/Source",
>>>> +//             "description": "An optional source location where the output
>>>> +//                             was produced."
>>>> +//           },
>>>> +//           "line": {
>>>> +//             "type": "integer",
>>>> +//             "description": "An optional source location line where the
>>>> +//                             output was produced."
>>>> +//           },
>>>> +//           "column": {
>>>> +//             "type": "integer",
>>>> +//             "description": "An optional source location column where the
>>>> +//                             output was produced."
>>>> +//           },
>>>> +//           "data": {
>>>> +//             "type":["array","boolean","integer","null","number","object",
>>>> +//                     "string"],
>>>> +//             "description": "Optional data to report. For the 'telemetry'
>>>> +//                             category the data will be sent to telemetry, for
>>>> +//                             the other categories the data is shown in JSON
>>>> +//                             format."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": ["output"]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "event", "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void VSCode::SendOutput(OutputType o, const llvm::StringRef output) {
>>>> +  if (output.empty())
>>>> +    return;
>>>> +
>>>> +  llvm::json::Object event(CreateEvent("output"));
>>>> +  llvm::json::Object body;
>>>> +  const char *category = nullptr;
>>>> +  switch (o) {
>>>> +  case OutputType::Console:
>>>> +    category = "console";
>>>> +    break;
>>>> +  case OutputType::Stdout:
>>>> +    category = "stdout";
>>>> +    break;
>>>> +  case OutputType::Stderr:
>>>> +    category = "stderr";
>>>> +    break;
>>>> +  case OutputType::Telemetry:
>>>> +    category = "telemetry";
>>>> +    break;
>>>> +  }
>>>> +  body.try_emplace("category", category);
>>>> +  body.try_emplace("output", output.str());
>>>> +  event.try_emplace("body", std::move(body));
>>>> +  SendJSON(llvm::json::Value(std::move(event)));
>>>> +}
>>>> +
>>>> +void __attribute__((format(printf, 3, 4)))
>>>> +VSCode::SendFormattedOutput(OutputType o, const char *format, ...) {
>>>> +  char buffer[1024];
>>>> +  va_list args;
>>>> +  va_start(args, format);
>>>> +  int actual_length = vsnprintf(buffer, sizeof(buffer), format, args);
>>>> +  va_end(args);
>>>> +  SendOutput(o, llvm::StringRef(buffer,
>>>> +                                std::min<int>(actual_length, sizeof(buffer))));
>>>> +}
>>>> +
>>>> +int64_t VSCode::GetNextSourceReference() {
>>>> +  static int64_t ref = 0;
>>>> +  return ++ref;
>>>> +}
>>>> +
>>>> +ExceptionBreakpoint *
>>>> +VSCode::GetExceptionBPFromStopReason(lldb::SBThread &thread) {
>>>> +  const auto num = thread.GetStopReasonDataCount();
>>>> +  // Check to see if have hit an exception breakpoint and change the
>>>> +  // reason to "exception", but only do so if all breakpoints that were
>>>> +  // hit are exception breakpoints.
>>>> +  ExceptionBreakpoint *exc_bp = nullptr;
>>>> +  for (size_t i = 0; i < num; i += 2) {
>>>> +    // thread.GetStopReasonDataAtIndex(i) will return the bp ID and
>>>> +    // thread.GetStopReasonDataAtIndex(i+1) will return the location
>>>> +    // within that breakpoint. We only care about the bp ID so we can
>>>> +    // see if this is an exception breakpoint that is getting hit.
>>>> +    lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
>>>> +    exc_bp = GetExceptionBreakpoint(bp_id);
>>>> +    // If any breakpoint is not an exception breakpoint, then stop and
>>>> +    // report this as a normal breakpoint
>>>> +    if (exc_bp == nullptr)
>>>> +      return nullptr;
>>>> +  }
>>>> +  return exc_bp;
>>>> +}
>>>> +
>>>> +lldb::SBThread VSCode::GetLLDBThread(const llvm::json::Object &arguments) {
>>>> +  auto tid = GetSigned(arguments, "threadId", LLDB_INVALID_THREAD_ID);
>>>> +  return target.GetProcess().GetThreadByID(tid);
>>>> +}
>>>> +
>>>> +lldb::SBFrame VSCode::GetLLDBFrame(const llvm::json::Object &arguments) {
>>>> +  const uint64_t frame_id = GetUnsigned(arguments, "frameId", UINT64_MAX);
>>>> +  lldb::SBProcess process = target.GetProcess();
>>>> +  // Upper 32 bits is the thread index ID
>>>> +  lldb::SBThread thread = process.GetThreadByIndexID(frame_id >> 32);
>>>> +  // Lower 32 bits is the frame index
>>>> +  return thread.GetFrameAtIndex(frame_id & 0xffffffffu);
>>>> +}
>>>> +
>>>> +llvm::json::Value VSCode::CreateTopLevelScopes() {
>>>> +  llvm::json::Array scopes;
>>>> +  scopes.emplace_back(CreateScope("Locals", VARREF_LOCALS, num_locals, false));
>>>> +  scopes.emplace_back(
>>>> +      CreateScope("Globals", VARREF_GLOBALS, num_globals, false));
>>>> +  scopes.emplace_back(CreateScope("Registers", VARREF_REGS, num_regs, false));
>>>> +  return llvm::json::Value(std::move(scopes));
>>>> +}
>>>> +
>>>> +void VSCode::RunLLDBCommands(llvm::StringRef prefix,
>>>> +                             const std::vector<std::string> &commands) {
>>>> +  SendOutput(OutputType::Console,
>>>> +             llvm::StringRef(::RunLLDBCommands(prefix, commands)));
>>>> +}
>>>> +
>>>> +void VSCode::RunInitCommands() {
>>>> +  RunLLDBCommands("Running initCommands:", init_commands);
>>>> +}
>>>> +
>>>> +void VSCode::RunPreRunCommands() {
>>>> +  RunLLDBCommands("Running preRunCommands:", pre_run_commands);
>>>> +}
>>>> +
>>>> +void VSCode::RunStopCommands() {
>>>> +  RunLLDBCommands("Running stopCommands:", stop_commands);
>>>> +}
>>>> +
>>>> +void VSCode::RunExitCommands() {
>>>> +  RunLLDBCommands("Running exitCommands:", exit_commands);
>>>> +}
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/VSCode.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/VSCode.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/VSCode.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/VSCode.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/VSCode.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,146 @@
>>>> +//===-- VSCode.h ------------------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_VSCODE_H_
>>>> +#define LLDBVSCODE_VSCODE_H_
>>>> +
>>>> +#include <iosfwd>
>>>> +#include <map>
>>>> +#include <set>
>>>> +#include <stdio.h>
>>>> +#include <thread>
>>>> +
>>>> +#include "llvm/ADT/DenseMap.h"
>>>> +#include "llvm/ADT/DenseSet.h"
>>>> +#include "llvm/ADT/StringMap.h"
>>>> +#include "llvm/ADT/StringRef.h"
>>>> +
>>>> +#include "lldb/API/SBAttachInfo.h"
>>>> +#include "lldb/API/SBBreakpoint.h"
>>>> +#include "lldb/API/SBBreakpointLocation.h"
>>>> +#include "lldb/API/SBCommandInterpreter.h"
>>>> +#include "lldb/API/SBCommandReturnObject.h"
>>>> +#include "lldb/API/SBCommunication.h"
>>>> +#include "lldb/API/SBDebugger.h"
>>>> +#include "lldb/API/SBEvent.h"
>>>> +#include "lldb/API/SBHostOS.h"
>>>> +#include "lldb/API/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/SBProcess.h"
>>>> +#include "lldb/API/SBStream.h"
>>>> +#include "lldb/API/SBStringList.h"
>>>> +#include "lldb/API/SBTarget.h"
>>>> +#include "lldb/API/SBThread.h"
>>>> +
>>>> +#include "ExceptionBreakpoint.h"
>>>> +#include "FunctionBreakpoint.h"
>>>> +#include "SourceBreakpoint.h"
>>>> +#include "SourceReference.h"
>>>> +
>>>> +#define VARREF_LOCALS (int64_t)1
>>>> +#define VARREF_GLOBALS (int64_t)2
>>>> +#define VARREF_REGS (int64_t)3
>>>> +#define VARREF_FIRST_VAR_IDX (int64_t)4
>>>> +#define VARREF_IS_SCOPE(v) (VARREF_LOCALS <= 1 && v < VARREF_FIRST_VAR_IDX)
>>>> +#define VARIDX_TO_VARREF(i) ((i) + VARREF_FIRST_VAR_IDX)
>>>> +#define VARREF_TO_VARIDX(v) ((v)-VARREF_FIRST_VAR_IDX)
>>>> +#define NO_TYPENAME "<no-type>"
>>>> +
>>>> +namespace lldb_vscode {
>>>> +
>>>> +typedef llvm::DenseMap<uint32_t, SourceBreakpoint> SourceBreakpointMap;
>>>> +typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap;
>>>> +enum class OutputType { Console, Stdout, Stderr, Telemetry };
>>>> +
>>>> +struct VSCode {
>>>> +  FILE *in;
>>>> +  FILE *out;
>>>> +  lldb::SBDebugger debugger;
>>>> +  lldb::SBTarget target;
>>>> +  lldb::SBAttachInfo attach_info;
>>>> +  lldb::SBLaunchInfo launch_info;
>>>> +  lldb::SBValueList variables;
>>>> +  lldb::SBBroadcaster broadcaster;
>>>> +  int64_t num_regs;
>>>> +  int64_t num_locals;
>>>> +  int64_t num_globals;
>>>> +  std::thread event_thread;
>>>> +  std::unique_ptr<std::ofstream> log;
>>>> +  llvm::DenseMap<lldb::addr_t, int64_t> addr_to_source_ref;
>>>> +  llvm::DenseMap<int64_t, SourceReference> source_map;
>>>> +  llvm::StringMap<SourceBreakpointMap> source_breakpoints;
>>>> +  FunctionBreakpointMap function_breakpoints;
>>>> +  std::vector<ExceptionBreakpoint> exception_breakpoints;
>>>> +  std::vector<std::string> init_commands;
>>>> +  std::vector<std::string> pre_run_commands;
>>>> +  std::vector<std::string> exit_commands;
>>>> +  std::vector<std::string> stop_commands;
>>>> +  lldb::tid_t focus_tid;
>>>> +  bool sent_terminated_event;
>>>> +  bool stop_at_entry;
>>>> +  // Keep track of the last stop thread index IDs as threads won't go away
>>>> +  // unless we send a "thread" event to indicate the thread exited.
>>>> +  llvm::DenseSet<lldb::tid_t> thread_ids;
>>>> +  VSCode();
>>>> +  ~VSCode();
>>>> +  VSCode(const VSCode &rhs) = delete;
>>>> +  void operator=(const VSCode &rhs) = delete;
>>>> +  void CloseInputStream();
>>>> +  void CloseOutputStream();
>>>> +  int64_t GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const;
>>>> +  ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter);
>>>> +  ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id);
>>>> +  //----------------------------------------------------------------------
>>>> +  // Send the JSON in "json_str" to the "out" stream. Correctly send the
>>>> +  // "Content-Length:" field followed by the length, followed by the raw
>>>> +  // JSON bytes.
>>>> +  //----------------------------------------------------------------------
>>>> +  void SendJSON(const std::string &json_str);
>>>> +
>>>> +  //----------------------------------------------------------------------
>>>> +  // Serialize the JSON value into a string and send the JSON packet to
>>>> +  // the "out" stream.
>>>> +  //----------------------------------------------------------------------
>>>> +  void SendJSON(const llvm::json::Value &json);
>>>> +
>>>> +  std::string ReadJSON();
>>>> +
>>>> +  void SendOutput(OutputType o, const llvm::StringRef output);
>>>> +
>>>> +  void __attribute__((format(printf, 3, 4)))
>>>> +  SendFormattedOutput(OutputType o, const char *format, ...);
>>>> +
>>>> +  static int64_t GetNextSourceReference();
>>>> +
>>>> +  ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread);
>>>> +
>>>> +  lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments);
>>>> +
>>>> +  lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
>>>> +
>>>> +  llvm::json::Value CreateTopLevelScopes();
>>>> +
>>>> +  void RunLLDBCommands(llvm::StringRef prefix,
>>>> +                       const std::vector<std::string> &commands);
>>>> +
>>>> +  void RunInitCommands();
>>>> +  void RunPreRunCommands();
>>>> +  void RunStopCommands();
>>>> +  void RunExitCommands();
>>>> +};
>>>> +
>>>> +extern VSCode g_vsc;
>>>> +
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/VSCodeForward.h
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/VSCodeForward.h?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/VSCodeForward.h?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/VSCodeForward.h (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/VSCodeForward.h Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,47 @@
>>>> +//===-- VSCodeForward.h -----------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#ifndef LLDBVSCODE_VSCODEFORWARD_H_
>>>> +#define LLDBVSCODE_VSCODEFORWARD_H_
>>>> +
>>>> +
>>>> +namespace lldb_vscode {
>>>> +struct BreakpointBase;
>>>> +struct ExceptionBreakpoint;
>>>> +struct FunctionBreakpoint;
>>>> +struct SourceBreakpoint;
>>>> +struct SourceReference;
>>>> +} // namespace lldb_vscode
>>>> +
>>>> +namespace lldb {
>>>> +class SBAttachInfo;
>>>> +class SBBreakpoint;
>>>> +class SBBreakpointLocation;
>>>> +class SBCommandInterpreter;
>>>> +class SBCommandReturnObject;
>>>> +class SBCommunication;
>>>> +class SBDebugger;
>>>> +class SBEvent;
>>>> +class SBFrame;
>>>> +class SBHostOS;
>>>> +class SBInstruction;
>>>> +class SBInstructionList;
>>>> +class SBLanguageRuntime;
>>>> +class SBLaunchInfo;
>>>> +class SBLineEntry;
>>>> +class SBListener;
>>>> +class SBProcess;
>>>> +class SBStream;
>>>> +class SBStringList;
>>>> +class SBTarget;
>>>> +class SBThread;
>>>> +class SBValue;
>>>> +} // namespace lldb
>>>> +
>>>> +#endif
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/lldb-vscode-Info.plist
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/lldb-vscode-Info.plist?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/lldb-vscode-Info.plist?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/lldb-vscode-Info.plist (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/lldb-vscode-Info.plist Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,21 @@
>>>> +<?xml version="1.0" encoding="UTF-8"?>
>>>> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd <http://www.apple.com/DTDs/PropertyList-1.0.dtd>">
>>>> +<plist version="1.0">
>>>> +<dict>
>>>> +	<key>CFBundleDevelopmentRegion</key>
>>>> +	<string>English</string>
>>>> +	<key>CFBundleIdentifier</key>
>>>> +	<string>com.apple.lldb-vscode</string>
>>>> +	<key>CFBundleInfoDictionaryVersion</key>
>>>> +	<string>6.0</string>
>>>> +	<key>CFBundleName</key>
>>>> +	<string>lldb-vscode</string>
>>>> +	<key>CFBundleVersion</key>
>>>> +	<string>360.99.0</string>
>>>> +	<key>SecTaskAccess</key>
>>>> +	<array>
>>>> +		<string>allowed</string>
>>>> +		<string>debug</string>
>>>> +	</array>
>>>> +</dict>
>>>> +</plist>
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/lldb-vscode.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/lldb-vscode.cpp?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/lldb-vscode.cpp?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/lldb-vscode.cpp (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/lldb-vscode.cpp Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,2706 @@
>>>> +//===-- lldb-vscode.cpp -----------------------------------------*- C++ -*-===//
>>>> +//
>>>> +//                     The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>> +//===----------------------------------------------------------------------===//
>>>> +
>>>> +#include <assert.h>
>>>> +#include <limits.h>
>>>> +#include <stdarg.h>
>>>> +#include <stdio.h>
>>>> +#include <stdlib.h>
>>>> +#include <string.h>
>>>> +#include <sys/stat.h>
>>>> +#include <sys/types.h>
>>>> +#if defined(_WIN32)
>>>> +// We need to #define NOMINMAX in order to skip `min()` and `max()` macro
>>>> +// definitions that conflict with other system headers.
>>>> +// We also need to #undef GetObject (which is defined to GetObjectW) because
>>>> +// the JSON code we use also has methods named `GetObject()` and we conflict
>>>> +// against these.
>>>> +#define NOMINMAX
>>>> +#include <windows.h>
>>>> +#undef GetObject
>>>> +#else
>>>> +#include <netinet/in.h>
>>>> +#include <sys/socket.h>
>>>> +#include <unistd.h>
>>>> +#endif
>>>> +
>>>> +#include <algorithm>
>>>> +#include <chrono>
>>>> +#include <fstream>
>>>> +#include <map>
>>>> +#include <memory>
>>>> +#include <mutex>
>>>> +#include <set>
>>>> +#include <sstream>
>>>> +#include <thread>
>>>> +
>>>> +#include "llvm/ADT/ArrayRef.h"
>>>> +#include "llvm/Support/FileSystem.h"
>>>> +#include "llvm/Support/raw_ostream.h"
>>>> +
>>>> +#include "JSONUtils.h"
>>>> +#include "LLDBUtils.h"
>>>> +#include "VSCode.h"
>>>> +
>>>> +#if defined(_WIN32)
>>>> +#define PATH_MAX MAX_PATH
>>>> +typedef int socklen_t;
>>>> +constexpr const char *dev_null_path = "nul";
>>>> +
>>>> +#else
>>>> +typedef int SOCKET;
>>>> +constexpr const char *dev_null_path = "/dev/null";
>>>> +
>>>> +#endif
>>>> +
>>>> +using namespace lldb_vscode;
>>>> +
>>>> +namespace {
>>>> +
>>>> +typedef void (*RequestCallback)(const llvm::json::Object &command);
>>>> +
>>>> +enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch };
>>>> +
>>>> +enum VSCodeBroadcasterBits { eBroadcastBitStopEventThread = 1u << 0 };
>>>> +
>>>> +int AcceptConnection(int portno) {
>>>> +  // Accept a socket connection from any host on "portno".
>>>> +  int newsockfd = -1;
>>>> +  struct sockaddr_in serv_addr, cli_addr;
>>>> +  SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
>>>> +  if (sockfd < 0) {
>>>> +    if (g_vsc.log)
>>>> +      *g_vsc.log << "error: opening socket (" << strerror(errno) << ")"
>>>> +                 << std::endl;
>>>> +  } else {
>>>> +    memset((char *)&serv_addr, 0, sizeof(serv_addr));
>>>> +    serv_addr.sin_family = AF_INET;
>>>> +    // serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
>>>> +    serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
>>>> +    serv_addr.sin_port = htons(portno);
>>>> +    if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
>>>> +      if (g_vsc.log)
>>>> +        *g_vsc.log << "error: binding socket (" << strerror(errno) << ")"
>>>> +                   << std::endl;
>>>> +    } else {
>>>> +      listen(sockfd, 5);
>>>> +      socklen_t clilen = sizeof(cli_addr);
>>>> +      newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
>>>> +      if (newsockfd < 0)
>>>> +        if (g_vsc.log)
>>>> +          *g_vsc.log << "error: accept (" << strerror(errno) << ")"
>>>> +                     << std::endl;
>>>> +    }
>>>> +#if defined(_WIN32)
>>>> +    closesocket(sockfd);
>>>> +#else
>>>> +    close(sockfd);
>>>> +#endif
>>>> +  }
>>>> +  return newsockfd;
>>>> +}
>>>> +
>>>> +std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) {
>>>> +  // Create and return an array of "const char *", one for each C string in
>>>> +  // "strs" and terminate the list with a NULL. This can be used for argument
>>>> +  // vectors (argv) or environment vectors (envp) like those passed to the
>>>> +  // "main" function in C programs.
>>>> +  std::vector<const char *> argv;
>>>> +  for (const auto &s : strs)
>>>> +    argv.push_back(s.c_str());
>>>> +  argv.push_back(nullptr);
>>>> +  return argv;
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Send a "exited" event to indicate the process has exited.
>>>> +//----------------------------------------------------------------------
>>>> +void SendProcessExitedEvent(lldb::SBProcess &process) {
>>>> +  llvm::json::Object event(CreateEvent("exited"));
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("exitCode", (int64_t)process.GetExitStatus());
>>>> +  event.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(event)));
>>>> +}
>>>> +
>>>> +void SendThreadExitedEvent(lldb::tid_t tid) {
>>>> +  llvm::json::Object event(CreateEvent("thread"));
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("reason", "exited");
>>>> +  body.try_emplace("threadId", (int64_t)tid);
>>>> +  event.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(event)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Send a "terminated" event to indicate the process is done being
>>>> +// debugged.
>>>> +//----------------------------------------------------------------------
>>>> +void SendTerminatedEvent() {
>>>> +  if (!g_vsc.sent_terminated_event) {
>>>> +    g_vsc.sent_terminated_event = true;
>>>> +    // Send a "terminated" event
>>>> +    llvm::json::Object event(CreateEvent("terminated"));
>>>> +    g_vsc.SendJSON(llvm::json::Value(std::move(event)));
>>>> +  }
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Send a thread stopped event for all threads as lons as the process
>>>> +// is stopped.
>>>> +//----------------------------------------------------------------------
>>>> +void SendThreadStoppedEvent() {
>>>> +  lldb::SBProcess process = g_vsc.target.GetProcess();
>>>> +  if (process.IsValid()) {
>>>> +    auto state = process.GetState();
>>>> +    if (state == lldb::eStateStopped) {
>>>> +      llvm::DenseSet<lldb::tid_t> old_thread_ids;
>>>> +      old_thread_ids.swap(g_vsc.thread_ids);
>>>> +      uint32_t stop_id = process.GetStopID();
>>>> +      const uint32_t num_threads = process.GetNumThreads();
>>>> +
>>>> +      // First make a pass through the threads to see if the focused thread
>>>> +      // has a stop reason. In case the focus thread doesn't have a stop
>>>> +      // reason, remember the first thread that has a stop reason so we can
>>>> +      // set it as the focus thread if below if needed.
>>>> +      lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID;
>>>> +      uint32_t num_threads_with_reason = 0;
>>>> +      for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
>>>> +        lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
>>>> +        const lldb::tid_t tid = thread.GetThreadID();
>>>> +        const bool has_reason = ThreadHasStopReason(thread);
>>>> +        // If the focus thread doesn't have a stop reason, clear the thread ID
>>>> +        if (tid == g_vsc.focus_tid && !has_reason)
>>>> +          g_vsc.focus_tid = LLDB_INVALID_THREAD_ID;
>>>> +        if (has_reason) {
>>>> +          ++num_threads_with_reason;
>>>> +          if (first_tid_with_reason == LLDB_INVALID_THREAD_ID)
>>>> +            first_tid_with_reason = tid;
>>>> +        }
>>>> +      }
>>>> +
>>>> +      // We will have cleared g_vsc.focus_tid if he focus thread doesn't
>>>> +      // have a stop reason, so if it was cleared, or wasn't set, then set the
>>>> +      // focus thread to the first thread with a stop reason.
>>>> +      if (g_vsc.focus_tid == LLDB_INVALID_THREAD_ID)
>>>> +        g_vsc.focus_tid = first_tid_with_reason;
>>>> +
>>>> +      // If no threads stopped with a reaspon, then report the first one so
>>>> +      // we at least let the UI know we stopped.
>>>> +      if (num_threads_with_reason == 0) {
>>>> +        lldb::SBThread thread = process.GetThreadAtIndex(0);
>>>> +        g_vsc.SendJSON(CreateThreadStopped(thread, stop_id));
>>>> +      } else {
>>>> +        for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
>>>> +          lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
>>>> +          g_vsc.thread_ids.insert(thread.GetThreadID());
>>>> +          if (ThreadHasStopReason(thread)) {
>>>> +            g_vsc.SendJSON(CreateThreadStopped(thread, stop_id));
>>>> +          }
>>>> +        }
>>>> +      }
>>>> +
>>>> +      for (auto tid : old_thread_ids) {
>>>> +        auto end = g_vsc.thread_ids.end();
>>>> +        auto pos = g_vsc.thread_ids.find(tid);
>>>> +        if (pos == end)
>>>> +          SendThreadExitedEvent(tid);
>>>> +      }
>>>> +    } else {
>>>> +      if (g_vsc.log)
>>>> +        *g_vsc.log << "error: SendThreadStoppedEvent() when process"
>>>> +                      " isn't stopped ("
>>>> +                   << lldb::SBDebugger::StateAsCString(state) << ')'
>>>> +                   << std::endl;
>>>> +    }
>>>> +  } else {
>>>> +    if (g_vsc.log)
>>>> +      *g_vsc.log << "error: SendThreadStoppedEvent() invalid process"
>>>> +                 << std::endl;
>>>> +  }
>>>> +  g_vsc.RunStopCommands();
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "ProcessEvent": {
>>>> +//   "allOf": [
>>>> +//     { "$ref": "#/definitions/Event" },
>>>> +//     {
>>>> +//       "type": "object",
>>>> +//       "description": "Event message for 'process' event type. The event
>>>> +//                       indicates that the debugger has begun debugging a
>>>> +//                       new process. Either one that it has launched, or one
>>>> +//                       that it has attached to.",
>>>> +//       "properties": {
>>>> +//         "event": {
>>>> +//           "type": "string",
>>>> +//           "enum": [ "process" ]
>>>> +//         },
>>>> +//         "body": {
>>>> +//           "type": "object",
>>>> +//           "properties": {
>>>> +//             "name": {
>>>> +//               "type": "string",
>>>> +//               "description": "The logical name of the process. This is
>>>> +//                               usually the full path to process's executable
>>>> +//                               file. Example: /home/myproj/program.js."
>>>> +//             },
>>>> +//             "systemProcessId": {
>>>> +//               "type": "integer",
>>>> +//               "description": "The system process id of the debugged process.
>>>> +//                               This property will be missing for non-system
>>>> +//                               processes."
>>>> +//             },
>>>> +//             "isLocalProcess": {
>>>> +//               "type": "boolean",
>>>> +//               "description": "If true, the process is running on the same
>>>> +//                               computer as the debug adapter."
>>>> +//             },
>>>> +//             "startMethod": {
>>>> +//               "type": "string",
>>>> +//               "enum": [ "launch", "attach", "attachForSuspendedLaunch" ],
>>>> +//               "description": "Describes how the debug engine started
>>>> +//                               debugging this process.",
>>>> +//               "enumDescriptions": [
>>>> +//                 "Process was launched under the debugger.",
>>>> +//                 "Debugger attached to an existing process.",
>>>> +//                 "A project launcher component has launched a new process in
>>>> +//                  a suspended state and then asked the debugger to attach."
>>>> +//               ]
>>>> +//             }
>>>> +//           },
>>>> +//           "required": [ "name" ]
>>>> +//         }
>>>> +//       },
>>>> +//       "required": [ "event", "body" ]
>>>> +//     }
>>>> +//   ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void SendProcessEvent(LaunchMethod launch_method) {
>>>> +  lldb::SBFileSpec exe_fspec = g_vsc.target.GetExecutable();
>>>> +  char exe_path[PATH_MAX];
>>>> +  exe_fspec.GetPath(exe_path, sizeof(exe_path));
>>>> +  llvm::json::Object event(CreateEvent("process"));
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("name", std::string(exe_path));
>>>> +  const auto pid = g_vsc.target.GetProcess().GetProcessID();
>>>> +  body.try_emplace("systemProcessId", (int64_t)pid);
>>>> +  body.try_emplace("isLocalProcess", true);
>>>> +  const char *startMethod = nullptr;
>>>> +  switch (launch_method) {
>>>> +  case Launch:
>>>> +    startMethod = "launch";
>>>> +    break;
>>>> +  case Attach:
>>>> +    startMethod = "attach";
>>>> +    break;
>>>> +  case AttachForSuspendedLaunch:
>>>> +    startMethod = "attachForSuspendedLaunch";
>>>> +    break;
>>>> +  }
>>>> +  body.try_emplace("startMethod", startMethod);
>>>> +  event.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(event)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Grab any STDOUT and STDERR from the process and send it up to VS Code
>>>> +// via an "output" event to the "stdout" and "stderr" categories.
>>>> +//----------------------------------------------------------------------
>>>> +void SendStdOutStdErr(lldb::SBProcess &process) {
>>>> +  char buffer[1024];
>>>> +  size_t count;
>>>> +  while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0)
>>>> +  g_vsc.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count));
>>>> +  while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0)
>>>> +    g_vsc.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// All events from a the debugger, target, process, thread and frames are
>>>> +// received in this function that runs in its own thread. We are using a
>>>> +// "FILE *" to output packets back to VS Code and they have mutexes in them
>>>> +// them prevent multiple threads from writing simultaneously so no locking
>>>> +// is required.
>>>> +//----------------------------------------------------------------------
>>>> +void EventThreadFunction() {
>>>> +  lldb::SBEvent event;
>>>> +  lldb::SBListener listener = g_vsc.debugger.GetListener();
>>>> +  bool done = false;
>>>> +  while (!done) {
>>>> +    if (listener.WaitForEvent(1, event)) {
>>>> +      const auto event_mask = event.GetType();
>>>> +      if (lldb::SBProcess::EventIsProcessEvent(event)) {
>>>> +        lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
>>>> +        if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
>>>> +          auto state = lldb::SBProcess::GetStateFromEvent(event);
>>>> +          switch (state) {
>>>> +          case lldb::eStateInvalid:
>>>> +            // Not a state event
>>>> +            break;
>>>> +          case lldb::eStateUnloaded:
>>>> +            break;
>>>> +          case lldb::eStateConnected:
>>>> +            break;
>>>> +          case lldb::eStateAttaching:
>>>> +            break;
>>>> +          case lldb::eStateLaunching:
>>>> +            break;
>>>> +          case lldb::eStateStepping:
>>>> +            break;
>>>> +          case lldb::eStateCrashed:
>>>> +            break;
>>>> +          case lldb::eStateDetached:
>>>> +            break;
>>>> +          case lldb::eStateSuspended:
>>>> +            break;
>>>> +          case lldb::eStateStopped:
>>>> +            // Only report a stopped event if the process was not restarted.
>>>> +            if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
>>>> +              SendStdOutStdErr(process);
>>>> +              SendThreadStoppedEvent();
>>>> +            }
>>>> +            break;
>>>> +          case lldb::eStateRunning:
>>>> +            break;
>>>> +          case lldb::eStateExited: {
>>>> +            // Run any exit LLDB commands the user specified in the
>>>> +            // launch.json
>>>> +            g_vsc.RunExitCommands();
>>>> +            SendProcessExitedEvent(process);
>>>> +            SendTerminatedEvent();
>>>> +            done = true;
>>>> +          } break;
>>>> +          }
>>>> +        } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
>>>> +                   (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
>>>> +          SendStdOutStdErr(process);
>>>> +        }
>>>> +      } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
>>>> +        if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
>>>> +          auto event_type =
>>>> +              lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
>>>> +          const auto num_locs =
>>>> +              lldb::SBBreakpoint::GetNumBreakpointLocationsFromEvent(event);
>>>> +          auto bp = lldb::SBBreakpoint::GetBreakpointFromEvent(event);
>>>> +          bool added = event_type & lldb::eBreakpointEventTypeLocationsAdded;
>>>> +          bool removed =
>>>> +              event_type & lldb::eBreakpointEventTypeLocationsRemoved;
>>>> +          if (added || removed) {
>>>> +            for (size_t i = 0; i < num_locs; ++i) {
>>>> +              auto bp_loc =
>>>> +                  lldb::SBBreakpoint::GetBreakpointLocationAtIndexFromEvent(
>>>> +                      event, i);
>>>> +              auto bp_event = CreateEvent("breakpoint");
>>>> +              llvm::json::Object body;
>>>> +              body.try_emplace("breakpoint", CreateBreakpoint(bp_loc));
>>>> +              if (added)
>>>> +                body.try_emplace("reason", "new");
>>>> +              else
>>>> +                body.try_emplace("reason", "removed");
>>>> +              bp_event.try_emplace("body", std::move(body));
>>>> +              g_vsc.SendJSON(llvm::json::Value(std::move(bp_event)));
>>>> +            }
>>>> +          }
>>>> +        }
>>>> +      } else if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) {
>>>> +        if (event_mask & eBroadcastBitStopEventThread) {
>>>> +          done = true;
>>>> +        }
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// Both attach and launch take a either a sourcePath or sourceMap
>>>> +// argument (or neither), from which we need to set the target.source-map.
>>>> +//----------------------------------------------------------------------
>>>> +void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
>>>> +  const char *sourceMapHelp =
>>>> +      "source must be be an array of two-element arrays, "
>>>> +      "each containing a source and replacement path string.\n";
>>>> +
>>>> +  std::string sourceMapCommand;
>>>> +  llvm::raw_string_ostream strm(sourceMapCommand);
>>>> +  strm << "settings set target.source-map ";
>>>> +  auto sourcePath = GetString(arguments, "sourcePath");
>>>> +
>>>> +  // sourceMap is the new, more general form of sourcePath and overrides it.
>>>> +  auto sourceMap = arguments.getArray("sourceMap");
>>>> +  if (sourceMap) {
>>>> +    for (const auto &value : *sourceMap) {
>>>> +      auto mapping = value.getAsArray();
>>>> +      if (mapping == nullptr || mapping->size() != 2 ||
>>>> +          (*mapping)[0].kind() != llvm::json::Value::String ||
>>>> +          (*mapping)[1].kind() != llvm::json::Value::String) {
>>>> +        g_vsc.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
>>>> +        return;
>>>> +      }
>>>> +      auto mapFrom = GetAsString((*mapping)[0]);
>>>> +      auto mapTo = GetAsString((*mapping)[1]);
>>>> +      strm << "\"" << mapFrom << "\" \"" << mapTo << "\"";
>>>> +    }
>>>> +  } else {
>>>> +    if (ObjectContainsKey(arguments, "sourceMap")) {
>>>> +      g_vsc.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
>>>> +      return;
>>>> +    }
>>>> +    if (sourcePath.empty())
>>>> +      return;
>>>> +    // Do any source remapping needed before we create our targets
>>>> +    strm << "\".\" \"" << sourcePath << "\"";
>>>> +  }
>>>> +  strm.flush();
>>>> +  if (!sourceMapCommand.empty()) {
>>>> +    g_vsc.RunLLDBCommands("Setting source map:", {sourceMapCommand});
>>>> +  }
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "AttachRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Attach request; value of command field is 'attach'.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "attach" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/AttachRequestArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments" ]
>>>> +//   }]
>>>> +// },
>>>> +// "AttachRequestArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'attach' request.\nThe attach request has no
>>>> +//   standardized attributes."
>>>> +// },
>>>> +// "AttachResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'attach' request. This is just an
>>>> +//     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_attach(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  lldb::SBError error;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  const lldb::pid_t pid =
>>>> +      GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID);
>>>> +  if (pid != LLDB_INVALID_PROCESS_ID)
>>>> +    g_vsc.attach_info.SetProcessID(pid);
>>>> +  const auto wait_for = GetBoolean(arguments, "waitFor", false);
>>>> +  g_vsc.attach_info.SetWaitForLaunch(wait_for, false /*async*/);
>>>> +  g_vsc.init_commands = GetStrings(arguments, "initCommands");
>>>> +  g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands");
>>>> +  g_vsc.stop_commands = GetStrings(arguments, "stopCommands");
>>>> +  g_vsc.exit_commands = GetStrings(arguments, "exitCommands");
>>>> +  auto attachCommands = GetStrings(arguments, "attachCommands");
>>>> +  g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
>>>> +  const auto debuggerRoot = GetString(arguments, "debuggerRoot");
>>>> +
>>>> +  // This is a hack for loading DWARF in .o files on Mac where the .o files
>>>> +  // in the debug map of the main executable have relative paths which require
>>>> +  // the lldb-vscode binary to have its working directory set to that relative
>>>> +  // root for the .o files in order to be able to load debug info.
>>>> +  if (!debuggerRoot.empty()) {
>>>> +    llvm::sys::fs::set_current_path(debuggerRoot.data());
>>>> +  }
>>>> +
>>>> +  // Run any initialize LLDB commands the user specified in the launch.json
>>>> +  g_vsc.RunInitCommands();
>>>> +
>>>> +  // Grab the name of the program we need to debug and set it as the first
>>>> +  // argument that will be passed to the program we will debug.
>>>> +  const auto program = GetString(arguments, "program");
>>>> +  if (!program.empty()) {
>>>> +    lldb::SBFileSpec program_fspec(program.data(), true /*resolve_path*/);
>>>> +
>>>> +    g_vsc.launch_info.SetExecutableFile(program_fspec,
>>>> +                                        false /*add_as_first_arg*/);
>>>> +    const char *target_triple = nullptr;
>>>> +    const char *uuid_cstr = nullptr;
>>>> +    // Stand alone debug info file if different from executable
>>>> +    const char *symfile = nullptr;
>>>> +    g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile);
>>>> +    if (error.Fail()) {
>>>> +      response.try_emplace("success", false);
>>>> +      response.try_emplace("message", std::string(error.GetCString()));
>>>> +      g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +      return;
>>>> +    }
>>>> +  }
>>>> +
>>>> +  const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
>>>> +  g_vsc.launch_info.SetDetachOnError(detatchOnError);
>>>> +
>>>> +  // Run any pre run LLDB commands the user specified in the launch.json
>>>> +  g_vsc.RunPreRunCommands();
>>>> +
>>>> +  if (pid == LLDB_INVALID_PROCESS_ID && wait_for) {
>>>> +    char attach_info[256];
>>>> +    auto attach_info_len =
>>>> +        snprintf(attach_info, sizeof(attach_info),
>>>> +                 "Waiting to attach to \"%s\"...", program.data());
>>>> +    g_vsc.SendOutput(OutputType::Console, llvm::StringRef(attach_info,
>>>> +                                                          attach_info_len));
>>>> +  }
>>>> +  if (attachCommands.empty()) {
>>>> +    // No "attachCommands", just attach normally.
>>>> +    // Disable async events so the attach will be successful when we return from
>>>> +    // the launch call and the launch will happen synchronously
>>>> +    g_vsc.debugger.SetAsync(false);
>>>> +    g_vsc.target.Attach(g_vsc.attach_info, error);
>>>> +    // Reenable async events
>>>> +    g_vsc.debugger.SetAsync(true);
>>>> +  } else {
>>>> +    // We have "attachCommands" that are a set of commands that are expected
>>>> +    // to execute the commands after which a process should be created. If there
>>>> +    // is no valid process after running these commands, we have failed.
>>>> +    g_vsc.RunLLDBCommands("Running attachCommands:", attachCommands);
>>>> +    // The custom commands might have created a new target so we should use the
>>>> +    // selected target after these commands are run.
>>>> +    g_vsc.target = g_vsc.debugger.GetSelectedTarget();
>>>> +  }
>>>> +
>>>> +  SetSourceMapFromArguments(*arguments);
>>>> +
>>>> +  if (error.Success()) {
>>>> +    auto attached_pid = g_vsc.target.GetProcess().GetProcessID();
>>>> +    if (attached_pid == LLDB_INVALID_PROCESS_ID) {
>>>> +      if (attachCommands.empty())
>>>> +        error.SetErrorString("failed to attach to a process");
>>>> +      else
>>>> +        error.SetErrorString("attachCommands failed to attach to a process");
>>>> +    }
>>>> +  }
>>>> +
>>>> +  if (error.Fail()) {
>>>> +    response.try_emplace("success", false);
>>>> +    response.try_emplace("message", std::string(error.GetCString()));
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +  if (error.Success()) {
>>>> +    SendProcessEvent(Attach);
>>>> +    g_vsc.SendJSON(CreateEvent("initialized"));
>>>> +    // SendThreadStoppedEvent();
>>>> +  }
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "ContinueRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Continue request; value of command field is 'continue'.
>>>> +//                     The request starts the debuggee to run again.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "continue" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/ContinueArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "ContinueArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'continue' request.",
>>>> +//   "properties": {
>>>> +//     "threadId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Continue execution for the specified thread (if
>>>> +//                       possible). If the backend cannot continue on a single
>>>> +//                       thread but will continue on all threads, it should
>>>> +//                       set the allThreadsContinued attribute in the response
>>>> +//                       to true."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "threadId" ]
>>>> +// },
>>>> +// "ContinueResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'continue' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "allThreadsContinued": {
>>>> +//             "type": "boolean",
>>>> +//             "description": "If true, the continue request has ignored the
>>>> +//                             specified thread and continued all threads
>>>> +//                             instead. If this attribute is missing a value
>>>> +//                             of 'true' is assumed for backward
>>>> +//                             compatibility."
>>>> +//           }
>>>> +//         }
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_continue(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  lldb::SBProcess process = g_vsc.target.GetProcess();
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  // Remember the thread ID that caused the resume so we can set the
>>>> +  // "threadCausedFocus" boolean value in the "stopped" events.
>>>> +  g_vsc.focus_tid = GetUnsigned(arguments, "threadId", LLDB_INVALID_THREAD_ID);
>>>> +  lldb::SBError error = process.Continue();
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("allThreadsContinued", true);
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "ConfigurationDoneRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//             "type": "object",
>>>> +//             "description": "ConfigurationDone request; value of command field
>>>> +//             is 'configurationDone'.\nThe client of the debug protocol must
>>>> +//             send this request at the end of the sequence of configuration
>>>> +//             requests (which was started by the InitializedEvent).",
>>>> +//             "properties": {
>>>> +//             "command": {
>>>> +//             "type": "string",
>>>> +//             "enum": [ "configurationDone" ]
>>>> +//             },
>>>> +//             "arguments": {
>>>> +//             "$ref": "#/definitions/ConfigurationDoneArguments"
>>>> +//             }
>>>> +//             },
>>>> +//             "required": [ "command" ]
>>>> +//             }]
>>>> +// },
>>>> +// "ConfigurationDoneArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'configurationDone' request.\nThe
>>>> +//   configurationDone request has no standardized attributes."
>>>> +// },
>>>> +// "ConfigurationDoneResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//             "type": "object",
>>>> +//             "description": "Response to 'configurationDone' request. This is
>>>> +//             just an acknowledgement, so no body field is required."
>>>> +//             }]
>>>> +// },
>>>> +//----------------------------------------------------------------------
>>>> +void request_configurationDone(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +  if (g_vsc.stop_at_entry)
>>>> +    SendThreadStoppedEvent();
>>>> +  else
>>>> +    g_vsc.target.GetProcess().Continue();
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "DisconnectRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Disconnect request; value of command field is
>>>> +//                     'disconnect'.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "disconnect" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/DisconnectArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command" ]
>>>> +//   }]
>>>> +// },
>>>> +// "DisconnectArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'disconnect' request.",
>>>> +//   "properties": {
>>>> +//     "terminateDebuggee": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "Indicates whether the debuggee should be terminated
>>>> +//                       when the debugger is disconnected. If unspecified,
>>>> +//                       the debug adapter is free to do whatever it thinks
>>>> +//                       is best. A client can only rely on this attribute
>>>> +//                       being properly honored if a debug adapter returns
>>>> +//                       true for the 'supportTerminateDebuggee' capability."
>>>> +//     },
>>>> +//     "restart": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "Indicates whether the debuggee should be restart
>>>> +//                       the process."
>>>> +//     }
>>>> +//   }
>>>> +// },
>>>> +// "DisconnectResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'disconnect' request. This is just an
>>>> +//                     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_disconnect(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +
>>>> +  bool terminateDebuggee = GetBoolean(arguments, "terminateDebuggee", false);
>>>> +  lldb::SBProcess process = g_vsc.target.GetProcess();
>>>> +  auto state = process.GetState();
>>>> +
>>>> +  switch (state) {
>>>> +  case lldb::eStateInvalid:
>>>> +  case lldb::eStateUnloaded:
>>>> +  case lldb::eStateDetached:
>>>> +  case lldb::eStateExited:
>>>> +    break;
>>>> +  case lldb::eStateConnected:
>>>> +  case lldb::eStateAttaching:
>>>> +  case lldb::eStateLaunching:
>>>> +  case lldb::eStateStepping:
>>>> +  case lldb::eStateCrashed:
>>>> +  case lldb::eStateSuspended:
>>>> +  case lldb::eStateStopped:
>>>> +  case lldb::eStateRunning:
>>>> +    g_vsc.debugger.SetAsync(false);
>>>> +    if (terminateDebuggee)
>>>> +      process.Kill();
>>>> +    else
>>>> +      process.Detach();
>>>> +    g_vsc.debugger.SetAsync(true);
>>>> +    break;
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +  SendTerminatedEvent();
>>>> +  if (g_vsc.event_thread.joinable()) {
>>>> +    g_vsc.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread);
>>>> +    g_vsc.event_thread.join();
>>>> +  }
>>>> +}
>>>> +
>>>> +void request_exceptionInfo(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  llvm::json::Object body;
>>>> +  lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
>>>> +  if (thread.IsValid()) {
>>>> +    auto stopReason = thread.GetStopReason();
>>>> +    if (stopReason == lldb::eStopReasonSignal)
>>>> +      body.try_emplace("exceptionId", "signal");
>>>> +    else if (stopReason == lldb::eStopReasonBreakpoint) {
>>>> +      ExceptionBreakpoint *exc_bp = g_vsc.GetExceptionBPFromStopReason(thread);
>>>> +      if (exc_bp) {
>>>> +        body.try_emplace("exceptionId", exc_bp->filter);
>>>> +        body.try_emplace("description", exc_bp->label);
>>>> +      } else {
>>>> +        body.try_emplace("exceptionId", "exception");
>>>> +      }
>>>> +    } else {
>>>> +      body.try_emplace("exceptionId", "exception");
>>>> +    }
>>>> +    if (!ObjectContainsKey(body, "description")) {
>>>> +      char description[1024];
>>>> +      if (thread.GetStopDescription(description, sizeof(description))) {
>>>> +        body.try_emplace("description", std::string(description));
>>>> +      }
>>>> +    }
>>>> +    body.try_emplace("breakMode", "always");
>>>> +    // auto excInfoCount = thread.GetStopReasonDataCount();
>>>> +    // for (auto i=0; i<excInfoCount; ++i) {
>>>> +    //   uint64_t exc_data = thread.GetStopReasonDataAtIndex(i);
>>>> +    // }
>>>> +  } else {
>>>> +    response.try_emplace("success", false);
>>>> +  }
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +//  "EvaluateRequest": {
>>>> +//    "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//      "type": "object",
>>>> +//      "description": "Evaluate request; value of command field is 'evaluate'.
>>>> +//                      Evaluates the given expression in the context of the
>>>> +//                      top most stack frame. The expression has access to any
>>>> +//                      variables and arguments that are in scope.",
>>>> +//      "properties": {
>>>> +//        "command": {
>>>> +//          "type": "string",
>>>> +//          "enum": [ "evaluate" ]
>>>> +//        },
>>>> +//        "arguments": {
>>>> +//          "$ref": "#/definitions/EvaluateArguments"
>>>> +//        }
>>>> +//      },
>>>> +//      "required": [ "command", "arguments"  ]
>>>> +//    }]
>>>> +//  },
>>>> +//  "EvaluateArguments": {
>>>> +//    "type": "object",
>>>> +//    "description": "Arguments for 'evaluate' request.",
>>>> +//    "properties": {
>>>> +//      "expression": {
>>>> +//        "type": "string",
>>>> +//        "description": "The expression to evaluate."
>>>> +//      },
>>>> +//      "frameId": {
>>>> +//        "type": "integer",
>>>> +//        "description": "Evaluate the expression in the scope of this stack
>>>> +//                        frame. If not specified, the expression is evaluated
>>>> +//                        in the global scope."
>>>> +//      },
>>>> +//      "context": {
>>>> +//        "type": "string",
>>>> +//        "_enum": [ "watch", "repl", "hover" ],
>>>> +//        "enumDescriptions": [
>>>> +//          "evaluate is run in a watch.",
>>>> +//          "evaluate is run from REPL console.",
>>>> +//          "evaluate is run from a data hover."
>>>> +//        ],
>>>> +//        "description": "The context in which the evaluate request is run."
>>>> +//      },
>>>> +//      "format": {
>>>> +//        "$ref": "#/definitions/ValueFormat",
>>>> +//        "description": "Specifies details on how to format the Evaluate
>>>> +//                        result."
>>>> +//      }
>>>> +//    },
>>>> +//    "required": [ "expression" ]
>>>> +//  },
>>>> +//  "EvaluateResponse": {
>>>> +//    "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//      "type": "object",
>>>> +//      "description": "Response to 'evaluate' request.",
>>>> +//      "properties": {
>>>> +//        "body": {
>>>> +//          "type": "object",
>>>> +//          "properties": {
>>>> +//            "result": {
>>>> +//              "type": "string",
>>>> +//              "description": "The result of the evaluate request."
>>>> +//            },
>>>> +//            "type": {
>>>> +//              "type": "string",
>>>> +//              "description": "The optional type of the evaluate result."
>>>> +//            },
>>>> +//            "presentationHint": {
>>>> +//              "$ref": "#/definitions/VariablePresentationHint",
>>>> +//              "description": "Properties of a evaluate result that can be
>>>> +//                              used to determine how to render the result in
>>>> +//                              the UI."
>>>> +//            },
>>>> +//            "variablesReference": {
>>>> +//              "type": "number",
>>>> +//              "description": "If variablesReference is > 0, the evaluate
>>>> +//                              result is structured and its children can be
>>>> +//                              retrieved by passing variablesReference to the
>>>> +//                              VariablesRequest."
>>>> +//            },
>>>> +//            "namedVariables": {
>>>> +//              "type": "number",
>>>> +//              "description": "The number of named child variables. The
>>>> +//                              client can use this optional information to
>>>> +//                              present the variables in a paged UI and fetch
>>>> +//                              them in chunks."
>>>> +//            },
>>>> +//            "indexedVariables": {
>>>> +//              "type": "number",
>>>> +//              "description": "The number of indexed child variables. The
>>>> +//                              client can use this optional information to
>>>> +//                              present the variables in a paged UI and fetch
>>>> +//                              them in chunks."
>>>> +//            }
>>>> +//          },
>>>> +//          "required": [ "result", "variablesReference" ]
>>>> +//        }
>>>> +//      },
>>>> +//      "required": [ "body" ]
>>>> +//    }]
>>>> +//  }
>>>> +//----------------------------------------------------------------------
>>>> +void request_evaluate(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Object body;
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
>>>> +  const auto expression = GetString(arguments, "expression");
>>>> +
>>>> +  if (!expression.empty() && expression[0] == '`') {
>>>> +    body.try_emplace("result",
>>>> +                     RunLLDBCommands(llvm::StringRef(),
>>>> +                                     {expression.substr(1)}));
>>>> +    body.try_emplace("variablesReference", (int64_t)0);
>>>> +  } else {
>>>> +    // Always try to get the answer from the local variables if possible. If
>>>> +    // this fails, then actually evaluate an expression using the expression
>>>> +    // parser. "frame variable" is more reliable than the expression parser in
>>>> +    // many cases and it is faster.
>>>> +    lldb::SBValue value = frame.GetValueForVariablePath(
>>>> +        expression.data(), lldb::eDynamicDontRunTarget);
>>>> +    if (value.GetError().Fail())
>>>> +      value = frame.EvaluateExpression(expression.data());
>>>> +    if (value.GetError().Fail()) {
>>>> +      response.try_emplace("success", false);
>>>> +      const char *error_cstr = value.GetError().GetCString();
>>>> +      if (error_cstr && error_cstr[0])
>>>> +        response.try_emplace("message", std::string(error_cstr));
>>>> +      else
>>>> +        response.try_emplace("message", "evaluate failed");
>>>> +    } else {
>>>> +      SetValueForKey(value, body, "result");
>>>> +      auto value_typename = value.GetType().GetDisplayTypeName();
>>>> +      body.try_emplace("type", value_typename ? value_typename : NO_TYPENAME);
>>>> +      if (value.MightHaveChildren()) {
>>>> +        auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize());
>>>> +        g_vsc.variables.Append(value);
>>>> +        body.try_emplace("variablesReference", variablesReference);
>>>> +      } else {
>>>> +        body.try_emplace("variablesReference", (int64_t)0);
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "InitializeRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Initialize request; value of command field is
>>>> +//                     'initialize'.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "initialize" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/InitializeRequestArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments" ]
>>>> +//   }]
>>>> +// },
>>>> +// "InitializeRequestArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'initialize' request.",
>>>> +//   "properties": {
>>>> +//     "clientID": {
>>>> +//       "type": "string",
>>>> +//       "description": "The ID of the (frontend) client using this adapter."
>>>> +//     },
>>>> +//     "adapterID": {
>>>> +//       "type": "string",
>>>> +//       "description": "The ID of the debug adapter."
>>>> +//     },
>>>> +//     "locale": {
>>>> +//       "type": "string",
>>>> +//       "description": "The ISO-639 locale of the (frontend) client using
>>>> +//                       this adapter, e.g. en-US or de-CH."
>>>> +//     },
>>>> +//     "linesStartAt1": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "If true all line numbers are 1-based (default)."
>>>> +//     },
>>>> +//     "columnsStartAt1": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "If true all column numbers are 1-based (default)."
>>>> +//     },
>>>> +//     "pathFormat": {
>>>> +//       "type": "string",
>>>> +//       "_enum": [ "path", "uri" ],
>>>> +//       "description": "Determines in what format paths are specified. The
>>>> +//                       default is 'path', which is the native format."
>>>> +//     },
>>>> +//     "supportsVariableType": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "Client supports the optional type attribute for
>>>> +//                       variables."
>>>> +//     },
>>>> +//     "supportsVariablePaging": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "Client supports the paging of variables."
>>>> +//     },
>>>> +//     "supportsRunInTerminalRequest": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "Client supports the runInTerminal request."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "adapterID" ]
>>>> +// },
>>>> +// "InitializeResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'initialize' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "$ref": "#/definitions/Capabilities",
>>>> +//         "description": "The capabilities of this debug adapter."
>>>> +//       }
>>>> +//     }
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_initialize(const llvm::json::Object &request) {
>>>> +  g_vsc.debugger = lldb::SBDebugger::Create(true /*source_init_files*/);
>>>> +  // Create an empty target right away since we might get breakpoint requests
>>>> +  // before we are given an executable to launch in a "launch" request, or a
>>>> +  // executable when attaching to a process by process ID in a "attach"
>>>> +  // request.
>>>> +  FILE *out = fopen(dev_null_path, "w");
>>>> +  if (out) {
>>>> +    // Set the output and error file handles to redirect into nothing otherwise
>>>> +    // if any code in LLDB prints to the debugger file handles, the output and
>>>> +    // error file handles are initialized to STDOUT and STDERR and any output
>>>> +    // will kill our debug session.
>>>> +    g_vsc.debugger.SetOutputFileHandle(out, true);
>>>> +    g_vsc.debugger.SetErrorFileHandle(out, false);
>>>> +  }
>>>> +
>>>> +  g_vsc.target = g_vsc.debugger.CreateTarget(nullptr);
>>>> +  lldb::SBListener listener = g_vsc.debugger.GetListener();
>>>> +  listener.StartListeningForEvents(
>>>> +      g_vsc.target.GetBroadcaster(),
>>>> +      lldb::SBTarget::eBroadcastBitBreakpointChanged);
>>>> +  listener.StartListeningForEvents(g_vsc.broadcaster,
>>>> +                                   eBroadcastBitStopEventThread);
>>>> +  // Start our event thread so we can receive events from the debugger, target,
>>>> +  // process and more.
>>>> +  g_vsc.event_thread = std::thread(EventThreadFunction);
>>>> +
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Object body;
>>>> +  // The debug adapter supports the configurationDoneRequest.
>>>> +  body.try_emplace("supportsConfigurationDoneRequest", true);
>>>> +  // The debug adapter supports function breakpoints.
>>>> +  body.try_emplace("supportsFunctionBreakpoints", true);
>>>> +  // The debug adapter supports conditional breakpoints.
>>>> +  body.try_emplace("supportsConditionalBreakpoints", true);
>>>> +  // The debug adapter supports breakpoints that break execution after a
>>>> +  // specified number of hits.
>>>> +  body.try_emplace("supportsHitConditionalBreakpoints", true);
>>>> +  // The debug adapter supports a (side effect free) evaluate request for
>>>> +  // data hovers.
>>>> +  body.try_emplace("supportsEvaluateForHovers", true);
>>>> +  // Available filters or options for the setExceptionBreakpoints request.
>>>> +  llvm::json::Array filters;
>>>> +  for (const auto &exc_bp : g_vsc.exception_breakpoints) {
>>>> +    filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
>>>> +  }
>>>> +  body.try_emplace("exceptionBreakpointFilters", std::move(filters));
>>>> +  // The debug adapter supports stepping back via the stepBack and
>>>> +  // reverseContinue requests.
>>>> +  body.try_emplace("supportsStepBack", false);
>>>> +  // The debug adapter supports setting a variable to a value.
>>>> +  body.try_emplace("supportsSetVariable", true);
>>>> +  // The debug adapter supports restarting a frame.
>>>> +  body.try_emplace("supportsRestartFrame", false);
>>>> +  // The debug adapter supports the gotoTargetsRequest.
>>>> +  body.try_emplace("supportsGotoTargetsRequest", false);
>>>> +  // The debug adapter supports the stepInTargetsRequest.
>>>> +  body.try_emplace("supportsStepInTargetsRequest", false);
>>>> +  // The debug adapter supports the completionsRequest.
>>>> +  body.try_emplace("supportsCompletionsRequest", false);
>>>> +  // The debug adapter supports the modules request.
>>>> +  body.try_emplace("supportsModulesRequest", false);
>>>> +  // The set of additional module information exposed by the debug adapter.
>>>> +  //   body.try_emplace("additionalModuleColumns"] = ColumnDescriptor
>>>> +  // Checksum algorithms supported by the debug adapter.
>>>> +  //   body.try_emplace("supportedChecksumAlgorithms"] = ChecksumAlgorithm
>>>> +  // The debug adapter supports the RestartRequest. In this case a client
>>>> +  // should not implement 'restart' by terminating and relaunching the adapter
>>>> +  // but by calling the RestartRequest.
>>>> +  body.try_emplace("supportsRestartRequest", false);
>>>> +  // The debug adapter supports 'exceptionOptions' on the
>>>> +  // setExceptionBreakpoints request.
>>>> +  body.try_emplace("supportsExceptionOptions", true);
>>>> +  // The debug adapter supports a 'format' attribute on the stackTraceRequest,
>>>> +  // variablesRequest, and evaluateRequest.
>>>> +  body.try_emplace("supportsValueFormattingOptions", true);
>>>> +  // The debug adapter supports the exceptionInfo request.
>>>> +  body.try_emplace("supportsExceptionInfoRequest", true);
>>>> +  // The debug adapter supports the 'terminateDebuggee' attribute on the
>>>> +  // 'disconnect' request.
>>>> +  body.try_emplace("supportTerminateDebuggee", true);
>>>> +  // The debug adapter supports the delayed loading of parts of the stack,
>>>> +  // which requires that both the 'startFrame' and 'levels' arguments and the
>>>> +  // 'totalFrames' result of the 'StackTrace' request are supported.
>>>> +  body.try_emplace("supportsDelayedStackTraceLoading", true);
>>>> +  // The debug adapter supports the 'loadedSources' request.
>>>> +  body.try_emplace("supportsLoadedSourcesRequest", false);
>>>> +
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "LaunchRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Launch request; value of command field is 'launch'.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "launch" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/LaunchRequestArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "LaunchRequestArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'launch' request.",
>>>> +//   "properties": {
>>>> +//     "noDebug": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "If noDebug is true the launch request should launch
>>>> +//                       the program without enabling debugging."
>>>> +//     }
>>>> +//   }
>>>> +// },
>>>> +// "LaunchResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'launch' request. This is just an
>>>> +//                     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_launch(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  lldb::SBError error;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  g_vsc.init_commands = GetStrings(arguments, "initCommands");
>>>> +  g_vsc.pre_run_commands = GetStrings(arguments, "preRunCommands");
>>>> +  g_vsc.stop_commands = GetStrings(arguments, "stopCommands");
>>>> +  g_vsc.exit_commands = GetStrings(arguments, "exitCommands");
>>>> +  g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false);
>>>> +  const auto debuggerRoot = GetString(arguments, "debuggerRoot");
>>>> +
>>>> +  // This is a hack for loading DWARF in .o files on Mac where the .o files
>>>> +  // in the debug map of the main executable have relative paths which require
>>>> +  // the lldb-vscode binary to have its working directory set to that relative
>>>> +  // root for the .o files in order to be able to load debug info.
>>>> +  if (!debuggerRoot.empty()) {
>>>> +    llvm::sys::fs::set_current_path(debuggerRoot.data());
>>>> +  }
>>>> +
>>>> +  SetSourceMapFromArguments(*arguments);
>>>> +
>>>> +  // Run any initialize LLDB commands the user specified in the launch.json
>>>> +  g_vsc.RunInitCommands();
>>>> +
>>>> +  // Grab the current working directory if there is one and set it in the
>>>> +  // launch info.
>>>> +  const auto cwd = GetString(arguments, "cwd");
>>>> +  if (!cwd.empty())
>>>> +    g_vsc.launch_info.SetWorkingDirectory(cwd.data());
>>>> +
>>>> +  // Grab the name of the program we need to debug and set it as the first
>>>> +  // argument that will be passed to the program we will debug.
>>>> +  const auto program = GetString(arguments, "program");
>>>> +  if (!program.empty()) {
>>>> +    lldb::SBFileSpec program_fspec(program.data(), true /*resolve_path*/);
>>>> +
>>>> +    g_vsc.launch_info.SetExecutableFile(program_fspec,
>>>> +                                        true /*add_as_first_arg*/);
>>>> +    const char *target_triple = nullptr;
>>>> +    const char *uuid_cstr = nullptr;
>>>> +    // Stand alone debug info file if different from executable
>>>> +    const char *symfile = nullptr;
>>>> +    g_vsc.target.AddModule(program.data(), target_triple, uuid_cstr, symfile);
>>>> +    if (error.Fail()) {
>>>> +      response.try_emplace("success", false);
>>>> +      response.try_emplace("message", std::string(error.GetCString()));
>>>> +      g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +    }
>>>> +  }
>>>> +
>>>> +  // Extract any extra arguments and append them to our program arguments for
>>>> +  // when we launch
>>>> +  auto args = GetStrings(arguments, "args");
>>>> +  if (!args.empty())
>>>> +    g_vsc.launch_info.SetArguments(MakeArgv(args).data(), true);
>>>> +
>>>> +  // Pass any environment variables along that the user specified.
>>>> +  auto envs = GetStrings(arguments, "env");
>>>> +  if (!envs.empty())
>>>> +    g_vsc.launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
>>>> +
>>>> +  auto flags = g_vsc.launch_info.GetLaunchFlags();
>>>> +
>>>> +  if (GetBoolean(arguments, "disableASLR", true))
>>>> +    flags |= lldb::eLaunchFlagDisableASLR;
>>>> +  if (GetBoolean(arguments, "disableSTDIO", false))
>>>> +    flags |= lldb::eLaunchFlagDisableSTDIO;
>>>> +  if (GetBoolean(arguments, "shellExpandArguments", false))
>>>> +    flags |= lldb::eLaunchFlagShellExpandArguments;
>>>> +  const bool detatchOnError = GetBoolean(arguments, "detachOnError", false);
>>>> +  g_vsc.launch_info.SetDetachOnError(detatchOnError);
>>>> +  g_vsc.launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
>>>> +                                   lldb::eLaunchFlagStopAtEntry);
>>>> +
>>>> +  // Run any pre run LLDB commands the user specified in the launch.json
>>>> +  g_vsc.RunPreRunCommands();
>>>> +
>>>> +  // Disable async events so the launch will be successful when we return from
>>>> +  // the launch call and the launch will happen synchronously
>>>> +  g_vsc.debugger.SetAsync(false);
>>>> +  g_vsc.target.Launch(g_vsc.launch_info, error);
>>>> +  if (error.Fail()) {
>>>> +    response.try_emplace("success", false);
>>>> +    response.try_emplace("message", std::string(error.GetCString()));
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +
>>>> +  SendProcessEvent(Launch);
>>>> +  g_vsc.SendJSON(llvm::json::Value(CreateEvent("initialized")));
>>>> +  // Reenable async events and start the event thread to catch async events.
>>>> +  g_vsc.debugger.SetAsync(true);
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "NextRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Next request; value of command field is 'next'. The
>>>> +//                     request starts the debuggee to run again for one step.
>>>> +//                     The debug adapter first sends the NextResponse and then
>>>> +//                     a StoppedEvent (event type 'step') after the step has
>>>> +//                     completed.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "next" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/NextArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "NextArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'next' request.",
>>>> +//   "properties": {
>>>> +//     "threadId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Execute 'next' for this thread."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "threadId" ]
>>>> +// },
>>>> +// "NextResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'next' request. This is just an
>>>> +//                     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_next(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
>>>> +  if (thread.IsValid()) {
>>>> +    // Remember the thread ID that caused the resume so we can set the
>>>> +    // "threadCausedFocus" boolean value in the "stopped" events.
>>>> +    g_vsc.focus_tid = thread.GetThreadID();
>>>> +    thread.StepOver();
>>>> +  } else {
>>>> +    response.try_emplace("success", false);
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "PauseRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Pause request; value of command field is 'pause'. The
>>>> +//     request suspenses the debuggee. The debug adapter first sends the
>>>> +//     PauseResponse and then a StoppedEvent (event type 'pause') after the
>>>> +//     thread has been paused successfully.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "pause" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/PauseArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "PauseArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'pause' request.",
>>>> +//   "properties": {
>>>> +//     "threadId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Pause execution for this thread."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "threadId" ]
>>>> +// },
>>>> +// "PauseResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'pause' request. This is just an
>>>> +//     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_pause(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  lldb::SBProcess process = g_vsc.target.GetProcess();
>>>> +  lldb::SBError error = process.Stop();
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "ScopesRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Scopes request; value of command field is 'scopes'. The
>>>> +//     request returns the variable scopes for a given stackframe ID.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "scopes" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/ScopesArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "ScopesArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'scopes' request.",
>>>> +//   "properties": {
>>>> +//     "frameId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Retrieve the scopes for this stackframe."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "frameId" ]
>>>> +// },
>>>> +// "ScopesResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'scopes' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "scopes": {
>>>> +//             "type": "array",
>>>> +//             "items": {
>>>> +//               "$ref": "#/definitions/Scope"
>>>> +//             },
>>>> +//             "description": "The scopes of the stackframe. If the array has
>>>> +//             length zero, there are no scopes available."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "scopes" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_scopes(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Object body;
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments);
>>>> +  g_vsc.variables.Clear();
>>>> +  g_vsc.variables.Append(frame.GetVariables(true,   // arguments
>>>> +                                            true,   // locals
>>>> +                                            false,  // statics
>>>> +                                            true)); // in_scope_only
>>>> +  g_vsc.num_locals = g_vsc.variables.GetSize();
>>>> +  g_vsc.variables.Append(frame.GetVariables(false,  // arguments
>>>> +                                            false,  // locals
>>>> +                                            true,   // statics
>>>> +                                            true)); // in_scope_only
>>>> +  g_vsc.num_globals = g_vsc.variables.GetSize() - (g_vsc.num_locals);
>>>> +  g_vsc.variables.Append(frame.GetRegisters());
>>>> +  g_vsc.num_regs =
>>>> +      g_vsc.variables.GetSize() - (g_vsc.num_locals + g_vsc.num_globals);
>>>> +  body.try_emplace("scopes", g_vsc.CreateTopLevelScopes());
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "SetBreakpointsRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "SetBreakpoints request; value of command field is
>>>> +//     'setBreakpoints'. Sets multiple breakpoints for a single source and
>>>> +//     clears all previous breakpoints in that source. To clear all breakpoint
>>>> +//     for a source, specify an empty array. When a breakpoint is hit, a
>>>> +//     StoppedEvent (event type 'breakpoint') is generated.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "setBreakpoints" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/SetBreakpointsArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "SetBreakpointsArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'setBreakpoints' request.",
>>>> +//   "properties": {
>>>> +//     "source": {
>>>> +//       "$ref": "#/definitions/Source",
>>>> +//       "description": "The source location of the breakpoints; either
>>>> +//       source.path or source.reference must be specified."
>>>> +//     },
>>>> +//     "breakpoints": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "$ref": "#/definitions/SourceBreakpoint"
>>>> +//       },
>>>> +//       "description": "The code locations of the breakpoints."
>>>> +//     },
>>>> +//     "lines": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "type": "integer"
>>>> +//       },
>>>> +//       "description": "Deprecated: The code locations of the breakpoints."
>>>> +//     },
>>>> +//     "sourceModified": {
>>>> +//       "type": "boolean",
>>>> +//       "description": "A value of true indicates that the underlying source
>>>> +//       has been modified which results in new breakpoint locations."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "source" ]
>>>> +// },
>>>> +// "SetBreakpointsResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'setBreakpoints' request. Returned is
>>>> +//     information about each breakpoint created by this request. This includes
>>>> +//     the actual code location and whether the breakpoint could be verified.
>>>> +//     The breakpoints returned are in the same order as the elements of the
>>>> +//     'breakpoints' (or the deprecated 'lines') in the
>>>> +//     SetBreakpointsArguments.", "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "breakpoints": {
>>>> +//             "type": "array",
>>>> +//             "items": {
>>>> +//               "$ref": "#/definitions/Breakpoint"
>>>> +//             },
>>>> +//             "description": "Information about the breakpoints. The array
>>>> +//             elements are in the same order as the elements of the
>>>> +//             'breakpoints' (or the deprecated 'lines') in the
>>>> +//             SetBreakpointsArguments."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "breakpoints" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// },
>>>> +// "SourceBreakpoint": {
>>>> +//   "type": "object",
>>>> +//   "description": "Properties of a breakpoint or logpoint passed to the
>>>> +//   setBreakpoints request.", "properties": {
>>>> +//     "line": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The source line of the breakpoint or logpoint."
>>>> +//     },
>>>> +//     "column": {
>>>> +//       "type": "integer",
>>>> +//       "description": "An optional source column of the breakpoint."
>>>> +//     },
>>>> +//     "condition": {
>>>> +//       "type": "string",
>>>> +//       "description": "An optional expression for conditional breakpoints."
>>>> +//     },
>>>> +//     "hitCondition": {
>>>> +//       "type": "string",
>>>> +//       "description": "An optional expression that controls how many hits of
>>>> +//       the breakpoint are ignored. The backend is expected to interpret the
>>>> +//       expression as needed."
>>>> +//     },
>>>> +//     "logMessage": {
>>>> +//       "type": "string",
>>>> +//       "description": "If this attribute exists and is non-empty, the backend
>>>> +//       must not 'break' (stop) but log the message instead. Expressions within
>>>> +//       {} are interpolated."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "line" ]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_setBreakpoints(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  lldb::SBError error;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  auto source = arguments->getObject("source");
>>>> +  const auto path = GetString(source, "path");
>>>> +  auto breakpoints = arguments->getArray("breakpoints");
>>>> +  llvm::json::Array response_breakpoints;
>>>> +  // Decode the source breakpoint infos for this "setBreakpoints" request
>>>> +  SourceBreakpointMap request_bps;
>>>> +  for (const auto &bp : *breakpoints) {
>>>> +    auto bp_obj = bp.getAsObject();
>>>> +    if (bp_obj) {
>>>> +      SourceBreakpoint src_bp(*bp_obj);
>>>> +      request_bps[src_bp.line] = std::move(src_bp);
>>>> +    }
>>>> +  }
>>>> +
>>>> +  // See if we already have breakpoints set for this source file from a
>>>> +  // previous "setBreakpoints" request
>>>> +  auto old_src_bp_pos = g_vsc.source_breakpoints.find(path);
>>>> +  if (old_src_bp_pos != g_vsc.source_breakpoints.end()) {
>>>> +
>>>> +    // We have already set breakpoints in this source file and they are giving
>>>> +    // use a new list of lines to set breakpoints on. Some breakpoints might
>>>> +    // already be set, and some might not. We need to remove any breakpoints
>>>> +    // whose lines are not contained in the any breakpoints lines in in the
>>>> +    // "breakpoints" array.
>>>> +
>>>> +    // Delete any breakpoints in this source file that aren't in the
>>>> +    // request_bps set. There is no call to remove breakpoints other than
>>>> +    // calling this function with a smaller or empty "breakpoints" list.
>>>> +    std::vector<uint32_t> remove_lines;
>>>> +    for (auto &pair: old_src_bp_pos->second) {
>>>> +      auto request_pos = request_bps.find(pair.first);
>>>> +      if (request_pos == request_bps.end()) {
>>>> +        // This breakpoint no longer exists in this source file, delete it
>>>> +        g_vsc.target.BreakpointDelete(pair.second.bp.GetID());
>>>> +        remove_lines.push_back(pair.first);
>>>> +      } else {
>>>> +        pair.second.UpdateBreakpoint(request_pos->second);
>>>> +        // Remove this breakpopint from the request breakpoints since we have
>>>> +        // handled it here and we don't need to set a new breakpoint below.
>>>> +        request_bps.erase(request_pos);
>>>> +        // Add this breakpoint info to the response
>>>> +        AppendBreakpoint(pair.second.bp, response_breakpoints);
>>>> +      }
>>>> +    }
>>>> +    // Remove any lines from this existing source breakpoint map
>>>> +    for (auto line: remove_lines)
>>>> +     old_src_bp_pos->second.erase(line);
>>>> +
>>>> +    // Now add any breakpoint infos left over in request_bps are the
>>>> +    // breakpoints that weren't set in this source file yet. We need to update
>>>> +    // thread source breakpoint info for the source file in the variable
>>>> +    // "old_src_bp_pos->second" so the info for this source file is up to date.
>>>> +    for (auto &pair : request_bps) {
>>>> +      pair.second.SetBreakpoint(path.data());
>>>> +      // Add this breakpoint info to the response
>>>> +      AppendBreakpoint(pair.second.bp, response_breakpoints);
>>>> +      old_src_bp_pos->second[pair.first] = std::move(pair.second);
>>>> +    }
>>>> +  } else {
>>>> +    // No breakpoints were set for this source file yet. Set all breakpoints
>>>> +    // for each line and add them to the response and create an entry in
>>>> +    // g_vsc.source_breakpoints for this source file.
>>>> +    for (auto &pair : request_bps) {
>>>> +      pair.second.SetBreakpoint(path.data());
>>>> +      // Add this breakpoint info to the response
>>>> +      AppendBreakpoint(pair.second.bp, response_breakpoints);
>>>> +    }
>>>> +    g_vsc.source_breakpoints[path] = std::move(request_bps);
>>>> +  }
>>>> +
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("breakpoints", std::move(response_breakpoints));
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "SetExceptionBreakpointsRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "SetExceptionBreakpoints request; value of command field
>>>> +//     is 'setExceptionBreakpoints'. The request configures the debuggers
>>>> +//     response to thrown exceptions. If an exception is configured to break, a
>>>> +//     StoppedEvent is fired (event type 'exception').", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "setExceptionBreakpoints" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/SetExceptionBreakpointsArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "SetExceptionBreakpointsArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'setExceptionBreakpoints' request.",
>>>> +//   "properties": {
>>>> +//     "filters": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "type": "string"
>>>> +//       },
>>>> +//       "description": "IDs of checked exception options. The set of IDs is
>>>> +//       returned via the 'exceptionBreakpointFilters' capability."
>>>> +//     },
>>>> +//     "exceptionOptions": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "$ref": "#/definitions/ExceptionOptions"
>>>> +//       },
>>>> +//       "description": "Configuration options for selected exceptions."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "filters" ]
>>>> +// },
>>>> +// "SetExceptionBreakpointsResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'setExceptionBreakpoints' request. This is
>>>> +//     just an acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_setExceptionBreakpoints(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  lldb::SBError error;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  auto filters = arguments->getArray("filters");
>>>> +  // Keep a list of any exception breakpoint filter names that weren't set
>>>> +  // so we can clear any exception breakpoints if needed.
>>>> +  std::set<std::string> unset_filters;
>>>> +  for (const auto &bp : g_vsc.exception_breakpoints)
>>>> +    unset_filters.insert(bp.filter);
>>>> +
>>>> +  for (const auto &value : *filters) {
>>>> +    const auto filter = GetAsString(value);
>>>> +    auto exc_bp = g_vsc.GetExceptionBreakpoint(filter);
>>>> +    if (exc_bp) {
>>>> +      exc_bp->SetBreakpoint();
>>>> +      unset_filters.erase(filter);
>>>> +    }
>>>> +  }
>>>> +  for (const auto &filter : unset_filters) {
>>>> +    auto exc_bp = g_vsc.GetExceptionBreakpoint(filter);
>>>> +    if (exc_bp)
>>>> +      exc_bp->ClearBreakpoint();
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "SetFunctionBreakpointsRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "SetFunctionBreakpoints request; value of command field is
>>>> +//     'setFunctionBreakpoints'. Sets multiple function breakpoints and clears
>>>> +//     all previous function breakpoints. To clear all function breakpoint,
>>>> +//     specify an empty array. When a function breakpoint is hit, a StoppedEvent
>>>> +//     (event type 'function breakpoint') is generated.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "setFunctionBreakpoints" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/SetFunctionBreakpointsArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "SetFunctionBreakpointsArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'setFunctionBreakpoints' request.",
>>>> +//   "properties": {
>>>> +//     "breakpoints": {
>>>> +//       "type": "array",
>>>> +//       "items": {
>>>> +//         "$ref": "#/definitions/FunctionBreakpoint"
>>>> +//       },
>>>> +//       "description": "The function names of the breakpoints."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "breakpoints" ]
>>>> +// },
>>>> +// "FunctionBreakpoint": {
>>>> +//   "type": "object",
>>>> +//   "description": "Properties of a breakpoint passed to the
>>>> +//   setFunctionBreakpoints request.", "properties": {
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "The name of the function."
>>>> +//     },
>>>> +//     "condition": {
>>>> +//       "type": "string",
>>>> +//       "description": "An optional expression for conditional breakpoints."
>>>> +//     },
>>>> +//     "hitCondition": {
>>>> +//       "type": "string",
>>>> +//       "description": "An optional expression that controls how many hits of
>>>> +//       the breakpoint are ignored. The backend is expected to interpret the
>>>> +//       expression as needed."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "name" ]
>>>> +// },
>>>> +// "SetFunctionBreakpointsResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'setFunctionBreakpoints' request. Returned is
>>>> +//     information about each breakpoint created by this request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "breakpoints": {
>>>> +//             "type": "array",
>>>> +//             "items": {
>>>> +//               "$ref": "#/definitions/Breakpoint"
>>>> +//             },
>>>> +//             "description": "Information about the breakpoints. The array
>>>> +//             elements correspond to the elements of the 'breakpoints' array."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "breakpoints" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_setFunctionBreakpoints(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  lldb::SBError error;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  auto breakpoints = arguments->getArray("breakpoints");
>>>> +  FunctionBreakpointMap request_bps;
>>>> +  llvm::json::Array response_breakpoints;
>>>> +  for (const auto &value : *breakpoints) {
>>>> +    auto bp_obj = value.getAsObject();
>>>> +    if (bp_obj == nullptr)
>>>> +      continue;
>>>> +    FunctionBreakpoint func_bp(*bp_obj);
>>>> +    request_bps[func_bp.functionName] = std::move(func_bp);
>>>> +  }
>>>> +
>>>> +  std::vector<llvm::StringRef> remove_names;
>>>> +  // Disable any function breakpoints that aren't in the request_bps.
>>>> +  // There is no call to remove function breakpoints other than calling this
>>>> +  // function with a smaller or empty "breakpoints" list.
>>>> +  for (auto &pair: g_vsc.function_breakpoints) {
>>>> +    auto request_pos = request_bps.find(pair.first());
>>>> +    if (request_pos == request_bps.end()) {
>>>> +      // This function breakpoint no longer exists delete it from LLDB
>>>> +      g_vsc.target.BreakpointDelete(pair.second.bp.GetID());
>>>> +      remove_names.push_back(pair.first());
>>>> +    } else {
>>>> +      // Update the existing breakpoint as any setting withing the function
>>>> +      // breakpoint might have changed.
>>>> +      pair.second.UpdateBreakpoint(request_pos->second);
>>>> +      // Remove this breakpopint from the request breakpoints since we have
>>>> +      // handled it here and we don't need to set a new breakpoint below.
>>>> +      request_bps.erase(request_pos);
>>>> +      // Add this breakpoint info to the response
>>>> +      AppendBreakpoint(pair.second.bp, response_breakpoints);
>>>> +    }
>>>> +  }
>>>> +  // Remove any breakpoints that are no longer in our list
>>>> +  for (const auto &name: remove_names)
>>>> +    g_vsc.function_breakpoints.erase(name);
>>>> +
>>>> +  // Any breakpoints that are left in "request_bps" are breakpoints that
>>>> +  // need to be set.
>>>> +  for (auto &pair : request_bps) {
>>>> +    pair.second.SetBreakpoint();
>>>> +    // Add this breakpoint info to the response
>>>> +    AppendBreakpoint(pair.second.bp, response_breakpoints);
>>>> +    g_vsc.function_breakpoints[pair.first()] = std::move(pair.second);
>>>> +  }
>>>> +
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("breakpoints", std::move(response_breakpoints));
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "SourceRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Source request; value of command field is 'source'. The
>>>> +//     request retrieves the source code for a given source reference.",
>>>> +//     "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "source" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/SourceArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "SourceArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'source' request.",
>>>> +//   "properties": {
>>>> +//     "source": {
>>>> +//       "$ref": "#/definitions/Source",
>>>> +//       "description": "Specifies the source content to load. Either
>>>> +//       source.path or source.sourceReference must be specified."
>>>> +//     },
>>>> +//     "sourceReference": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The reference to the source. This is the same as
>>>> +//       source.sourceReference. This is provided for backward compatibility
>>>> +//       since old backends do not understand the 'source' attribute."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "sourceReference" ]
>>>> +// },
>>>> +// "SourceResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'source' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "content": {
>>>> +//             "type": "string",
>>>> +//             "description": "Content of the source reference."
>>>> +//           },
>>>> +//           "mimeType": {
>>>> +//             "type": "string",
>>>> +//             "description": "Optional content type (mime type) of the source."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "content" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_source(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Object body;
>>>> +
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  auto source = arguments->getObject("source");
>>>> +  auto sourceReference = GetSigned(source, "sourceReference", -1);
>>>> +  auto pos = g_vsc.source_map.find((lldb::addr_t)sourceReference);
>>>> +  if (pos != g_vsc.source_map.end()) {
>>>> +    body.try_emplace("content", pos->second.content);
>>>> +  } else {
>>>> +    response.try_emplace("success", false);
>>>> +  }
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "StackTraceRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "StackTrace request; value of command field is
>>>> +//     'stackTrace'. The request returns a stacktrace from the current execution
>>>> +//     state.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "stackTrace" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/StackTraceArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "StackTraceArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'stackTrace' request.",
>>>> +//   "properties": {
>>>> +//     "threadId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Retrieve the stacktrace for this thread."
>>>> +//     },
>>>> +//     "startFrame": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The index of the first frame to return; if omitted
>>>> +//       frames start at 0."
>>>> +//     },
>>>> +//     "levels": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The maximum number of frames to return. If levels is
>>>> +//       not specified or 0, all frames are returned."
>>>> +//     },
>>>> +//     "format": {
>>>> +//       "$ref": "#/definitions/StackFrameFormat",
>>>> +//       "description": "Specifies details on how to format the stack frames."
>>>> +//     }
>>>> +//  },
>>>> +//   "required": [ "threadId" ]
>>>> +// },
>>>> +// "StackTraceResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'stackTrace' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "stackFrames": {
>>>> +//             "type": "array",
>>>> +//             "items": {
>>>> +//               "$ref": "#/definitions/StackFrame"
>>>> +//             },
>>>> +//             "description": "The frames of the stackframe. If the array has
>>>> +//             length zero, there are no stackframes available. This means that
>>>> +//             there is no location information available."
>>>> +//           },
>>>> +//           "totalFrames": {
>>>> +//             "type": "integer",
>>>> +//             "description": "The total number of frames available."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "stackFrames" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_stackTrace(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  lldb::SBError error;
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
>>>> +  llvm::json::Array stackFrames;
>>>> +  llvm::json::Object body;
>>>> +
>>>> +  if (thread.IsValid()) {
>>>> +    const auto startFrame = GetUnsigned(arguments, "startFrame", 0);
>>>> +    const auto levels = GetUnsigned(arguments, "levels", 0);
>>>> +    const auto endFrame = (levels == 0) ? INT64_MAX : (startFrame + levels);
>>>> +    for (uint32_t i = startFrame; i < endFrame; ++i) {
>>>> +      auto frame = thread.GetFrameAtIndex(i);
>>>> +      if (!frame.IsValid())
>>>> +        break;
>>>> +      stackFrames.emplace_back(CreateStackFrame(frame));
>>>> +    }
>>>> +  }
>>>> +  body.try_emplace("stackFrames", std::move(stackFrames));
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "StepInRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "StepIn request; value of command field is 'stepIn'. The
>>>> +//     request starts the debuggee to step into a function/method if possible.
>>>> +//     If it cannot step into a target, 'stepIn' behaves like 'next'. The debug
>>>> +//     adapter first sends the StepInResponse and then a StoppedEvent (event
>>>> +//     type 'step') after the step has completed. If there are multiple
>>>> +//     function/method calls (or other targets) on the source line, the optional
>>>> +//     argument 'targetId' can be used to control into which target the 'stepIn'
>>>> +//     should occur. The list of possible targets for a given source line can be
>>>> +//     retrieved via the 'stepInTargets' request.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "stepIn" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/StepInArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "StepInArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'stepIn' request.",
>>>> +//   "properties": {
>>>> +//     "threadId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Execute 'stepIn' for this thread."
>>>> +//     },
>>>> +//     "targetId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Optional id of the target to step into."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "threadId" ]
>>>> +// },
>>>> +// "StepInResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'stepIn' request. This is just an
>>>> +//     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_stepIn(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
>>>> +  if (thread.IsValid()) {
>>>> +    // Remember the thread ID that caused the resume so we can set the
>>>> +    // "threadCausedFocus" boolean value in the "stopped" events.
>>>> +    g_vsc.focus_tid = thread.GetThreadID();
>>>> +    thread.StepInto();
>>>> +  } else {
>>>> +    response.try_emplace("success", false);
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "StepOutRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "StepOut request; value of command field is 'stepOut'. The
>>>> +//     request starts the debuggee to run again for one step. The debug adapter
>>>> +//     first sends the StepOutResponse and then a StoppedEvent (event type
>>>> +//     'step') after the step has completed.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "stepOut" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/StepOutArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "StepOutArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'stepOut' request.",
>>>> +//   "properties": {
>>>> +//     "threadId": {
>>>> +//       "type": "integer",
>>>> +//       "description": "Execute 'stepOut' for this thread."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "threadId" ]
>>>> +// },
>>>> +// "StepOutResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'stepOut' request. This is just an
>>>> +//     acknowledgement, so no body field is required."
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_stepOut(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  lldb::SBThread thread = g_vsc.GetLLDBThread(*arguments);
>>>> +  if (thread.IsValid()) {
>>>> +    // Remember the thread ID that caused the resume so we can set the
>>>> +    // "threadCausedFocus" boolean value in the "stopped" events.
>>>> +    g_vsc.focus_tid = thread.GetThreadID();
>>>> +    thread.StepOut();
>>>> +  } else {
>>>> +    response.try_emplace("success", false);
>>>> +  }
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "ThreadsRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Thread request; value of command field is 'threads'. The
>>>> +//     request retrieves a list of all threads.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "threads" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command" ]
>>>> +//   }]
>>>> +// },
>>>> +// "ThreadsResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'threads' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "threads": {
>>>> +//             "type": "array",
>>>> +//             "items": {
>>>> +//               "$ref": "#/definitions/Thread"
>>>> +//             },
>>>> +//             "description": "All threads."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "threads" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_threads(const llvm::json::Object &request) {
>>>> +
>>>> +  lldb::SBProcess process = g_vsc.target.GetProcess();
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +
>>>> +  const uint32_t num_threads = process.GetNumThreads();
>>>> +  llvm::json::Array threads;
>>>> +  for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
>>>> +    lldb::SBThread thread = process.GetThreadAtIndex(thread_idx);
>>>> +    threads.emplace_back(CreateThread(thread));
>>>> +  }
>>>> +  if (threads.size() == 0) {
>>>> +    response.try_emplace("success", false);
>>>> +  }
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("threads", std::move(threads));
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "SetVariableRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "setVariable request; value of command field is
>>>> +//     'setVariable'. Set the variable with the given name in the variable
>>>> +//     container to a new value.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "setVariable" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/SetVariableArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "SetVariableArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'setVariable' request.",
>>>> +//   "properties": {
>>>> +//     "variablesReference": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The reference of the variable container."
>>>> +//     },
>>>> +//     "name": {
>>>> +//       "type": "string",
>>>> +//       "description": "The name of the variable."
>>>> +//     },
>>>> +//     "value": {
>>>> +//       "type": "string",
>>>> +//       "description": "The value of the variable."
>>>> +//     },
>>>> +//     "format": {
>>>> +//       "$ref": "#/definitions/ValueFormat",
>>>> +//       "description": "Specifies details on how to format the response value."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "variablesReference", "name", "value" ]
>>>> +// },
>>>> +// "SetVariableResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'setVariable' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "value": {
>>>> +//             "type": "string",
>>>> +//             "description": "The new value of the variable."
>>>> +//           },
>>>> +//           "type": {
>>>> +//             "type": "string",
>>>> +//             "description": "The type of the new value. Typically shown in the
>>>> +//             UI when hovering over the value."
>>>> +//           },
>>>> +//           "variablesReference": {
>>>> +//             "type": "number",
>>>> +//             "description": "If variablesReference is > 0, the new value is
>>>> +//             structured and its children can be retrieved by passing
>>>> +//             variablesReference to the VariablesRequest."
>>>> +//           },
>>>> +//           "namedVariables": {
>>>> +//             "type": "number",
>>>> +//             "description": "The number of named child variables. The client
>>>> +//             can use this optional information to present the variables in a
>>>> +//             paged UI and fetch them in chunks."
>>>> +//           },
>>>> +//           "indexedVariables": {
>>>> +//             "type": "number",
>>>> +//             "description": "The number of indexed child variables. The client
>>>> +//             can use this optional information to present the variables in a
>>>> +//             paged UI and fetch them in chunks."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "value" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_setVariable(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Array variables;
>>>> +  llvm::json::Object body;
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  // This is a reference to the containing variable/scope
>>>> +  const auto variablesReference =
>>>> +      GetUnsigned(arguments, "variablesReference", 0);
>>>> +  const auto name = GetString(arguments, "name");
>>>> +  const auto value = GetString(arguments, "value");
>>>> +  // Set success to false just in case we don't find the variable by name
>>>> +  response.try_emplace("success", false);
>>>> +
>>>> +  lldb::SBValue variable;
>>>> +  int64_t newVariablesReference = 0;
>>>> +
>>>> +  // The "id" is the unique integer ID that is unique within the enclosing
>>>> +  // variablesReference. It is optionally added to any "interface Variable"
>>>> +  // objects to uniquely identify a variable within an enclosing
>>>> +  // variablesReference. It helps to disambiguate between two variables that
>>>> +  // have the same name within the same scope since the "setVariables" request
>>>> +  // only specifies the variable reference of the enclosing scope/variable, and
>>>> +  // the name of the variable. We could have two shadowed variables with the
>>>> +  // same name in "Locals" or "Globals". In our case the "id" absolute index
>>>> +  // of the variable within the the g_vsc.variables list.
>>>> +  const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX);
>>>> +  if (id_value != UINT64_MAX) {
>>>> +    variable = g_vsc.variables.GetValueAtIndex(id_value);
>>>> +  } else if (VARREF_IS_SCOPE(variablesReference)) {
>>>> +    // variablesReference is one of our scopes, not an actual variable it is
>>>> +    // asking for a variable inlocals or globals or registers
>>>> +    int64_t start_idx = 0;
>>>> +    int64_t end_idx = 0;
>>>> +    switch (variablesReference) {
>>>> +    case VARREF_LOCALS:
>>>> +      start_idx = 0;
>>>> +      end_idx = start_idx + g_vsc.num_locals;
>>>> +      break;
>>>> +    case VARREF_GLOBALS:
>>>> +      start_idx = g_vsc.num_locals;
>>>> +      end_idx = start_idx + g_vsc.num_globals;
>>>> +      break;
>>>> +    case VARREF_REGS:
>>>> +      start_idx = g_vsc.num_locals + g_vsc.num_globals;
>>>> +      end_idx = start_idx + g_vsc.num_regs;
>>>> +      break;
>>>> +    default:
>>>> +      break;
>>>> +    }
>>>> +
>>>> +    // Find the variable by name in the correct scope and hope we don't have
>>>> +    // multiple variables with the same name. We search backwards because
>>>> +    // the list of variables has the top most variables first and variables
>>>> +    // in deeper scopes are last. This means we will catch the deepest
>>>> +    // variable whose name matches which is probably what the user wants.
>>>> +    for (int64_t i = end_idx - 1; i >= start_idx; --i) {
>>>> +      auto curr_variable = g_vsc.variables.GetValueAtIndex(i);
>>>> +      llvm::StringRef variable_name(curr_variable.GetName());
>>>> +      if (variable_name == name) {
>>>> +        variable = curr_variable;
>>>> +        if (curr_variable.MightHaveChildren())
>>>> +          newVariablesReference = i;
>>>> +        break;
>>>> +      }
>>>> +    }
>>>> +  } else {
>>>> +    // We have a named item within an actual variable so we need to find it
>>>> +    // withing the container variable by name.
>>>> +    const int64_t var_idx = VARREF_TO_VARIDX(variablesReference);
>>>> +    lldb::SBValue container = g_vsc.variables.GetValueAtIndex(var_idx);
>>>> +    variable = container.GetChildMemberWithName(name.data());
>>>> +    if (!variable.IsValid()) {
>>>> +      if (name.startswith("[")) {
>>>> +        llvm::StringRef index_str(name.drop_front(1));
>>>> +        uint64_t index = 0;
>>>> +        if (!index_str.consumeInteger(0, index)) {
>>>> +          if (index_str == "]")
>>>> +            variable = container.GetChildAtIndex(index);
>>>> +        }
>>>> +      }
>>>> +    }
>>>> +
>>>> +    // We don't know the index of the variable in our g_vsc.variables
>>>> +    if (variable.IsValid()) {
>>>> +      if (variable.MightHaveChildren()) {
>>>> +        newVariablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize());
>>>> +        g_vsc.variables.Append(variable);
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +
>>>> +  if (variable.IsValid()) {
>>>> +    lldb::SBError error;
>>>> +    bool success = variable.SetValueFromCString(value.data(), error);
>>>> +    if (success) {
>>>> +      SetValueForKey(variable, body, "value");
>>>> +      body.try_emplace("type", variable.GetType().GetDisplayTypeName());
>>>> +      body.try_emplace("variablesReference", newVariablesReference);
>>>> +    } else {
>>>> +      body.try_emplace("message", std::string(error.GetCString()));
>>>> +    }
>>>> +    response.try_emplace("success", success);
>>>> +  }
>>>> +
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +//----------------------------------------------------------------------
>>>> +// "VariablesRequest": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Request" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Variables request; value of command field is 'variables'.
>>>> +//     Retrieves all child variables for the given variable reference. An
>>>> +//     optional filter can be used to limit the fetched children to either named
>>>> +//     or indexed children.", "properties": {
>>>> +//       "command": {
>>>> +//         "type": "string",
>>>> +//         "enum": [ "variables" ]
>>>> +//       },
>>>> +//       "arguments": {
>>>> +//         "$ref": "#/definitions/VariablesArguments"
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "command", "arguments"  ]
>>>> +//   }]
>>>> +// },
>>>> +// "VariablesArguments": {
>>>> +//   "type": "object",
>>>> +//   "description": "Arguments for 'variables' request.",
>>>> +//   "properties": {
>>>> +//     "variablesReference": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The Variable reference."
>>>> +//     },
>>>> +//     "filter": {
>>>> +//       "type": "string",
>>>> +//       "enum": [ "indexed", "named" ],
>>>> +//       "description": "Optional filter to limit the child variables to either
>>>> +//       named or indexed. If ommited, both types are fetched."
>>>> +//     },
>>>> +//     "start": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The index of the first variable to return; if omitted
>>>> +//       children start at 0."
>>>> +//     },
>>>> +//     "count": {
>>>> +//       "type": "integer",
>>>> +//       "description": "The number of variables to return. If count is missing
>>>> +//       or 0, all variables are returned."
>>>> +//     },
>>>> +//     "format": {
>>>> +//       "$ref": "#/definitions/ValueFormat",
>>>> +//       "description": "Specifies details on how to format the Variable
>>>> +//       values."
>>>> +//     }
>>>> +//   },
>>>> +//   "required": [ "variablesReference" ]
>>>> +// },
>>>> +// "VariablesResponse": {
>>>> +//   "allOf": [ { "$ref": "#/definitions/Response" }, {
>>>> +//     "type": "object",
>>>> +//     "description": "Response to 'variables' request.",
>>>> +//     "properties": {
>>>> +//       "body": {
>>>> +//         "type": "object",
>>>> +//         "properties": {
>>>> +//           "variables": {
>>>> +//             "type": "array",
>>>> +//             "items": {
>>>> +//               "$ref": "#/definitions/Variable"
>>>> +//             },
>>>> +//             "description": "All (or a range) of variables for the given
>>>> +//             variable reference."
>>>> +//           }
>>>> +//         },
>>>> +//         "required": [ "variables" ]
>>>> +//       }
>>>> +//     },
>>>> +//     "required": [ "body" ]
>>>> +//   }]
>>>> +// }
>>>> +//----------------------------------------------------------------------
>>>> +void request_variables(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Array variables;
>>>> +  auto arguments = request.getObject("arguments");
>>>> +  const auto variablesReference =
>>>> +      GetUnsigned(arguments, "variablesReference", 0);
>>>> +  const int64_t start = GetSigned(arguments, "start", 0);
>>>> +  const int64_t count = GetSigned(arguments, "count", 0);
>>>> +  bool hex = false;
>>>> +  auto format = arguments->getObject("format");
>>>> +  if (format)
>>>> +    hex = GetBoolean(format, "hex", false);
>>>> +
>>>> +  if (VARREF_IS_SCOPE(variablesReference)) {
>>>> +    // variablesReference is one of our scopes, not an actual variable it is
>>>> +    // asking for the list of args, locals or globals.
>>>> +    int64_t start_idx = 0;
>>>> +    int64_t num_children = 0;
>>>> +    switch (variablesReference) {
>>>> +    case VARREF_LOCALS:
>>>> +      start_idx = start;
>>>> +      num_children = g_vsc.num_locals;
>>>> +      break;
>>>> +    case VARREF_GLOBALS:
>>>> +      start_idx = start + g_vsc.num_locals + start;
>>>> +      num_children = g_vsc.num_globals;
>>>> +      break;
>>>> +    case VARREF_REGS:
>>>> +      start_idx = start + g_vsc.num_locals + g_vsc.num_globals;
>>>> +      num_children = g_vsc.num_regs;
>>>> +      break;
>>>> +    default:
>>>> +      break;
>>>> +    }
>>>> +    const int64_t end_idx = start_idx + ((count == 0) ? num_children : count);
>>>> +    for (auto i = start_idx; i < end_idx; ++i) {
>>>> +      lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(i);
>>>> +      if (!variable.IsValid())
>>>> +        break;
>>>> +      variables.emplace_back(
>>>> +          CreateVariable(variable, VARIDX_TO_VARREF(i), i, hex));
>>>> +    }
>>>> +  } else {
>>>> +    // We are expanding a variable that has children, so we will return its
>>>> +    // children.
>>>> +    const int64_t var_idx = VARREF_TO_VARIDX(variablesReference);
>>>> +    lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(var_idx);
>>>> +    if (variable.IsValid()) {
>>>> +      const auto num_children = variable.GetNumChildren();
>>>> +      const int64_t end_idx = start + ((count == 0) ? num_children : count);
>>>> +      for (auto i = start; i < end_idx; ++i) {
>>>> +        lldb::SBValue child = variable.GetChildAtIndex(i);
>>>> +        if (!child.IsValid())
>>>> +          break;
>>>> +        if (child.MightHaveChildren()) {
>>>> +          const int64_t var_idx = g_vsc.variables.GetSize();
>>>> +          auto childVariablesReferences = VARIDX_TO_VARREF(var_idx);
>>>> +          variables.emplace_back(
>>>> +              CreateVariable(child, childVariablesReferences, var_idx, hex));
>>>> +          g_vsc.variables.Append(child);
>>>> +        } else {
>>>> +          variables.emplace_back(CreateVariable(child, 0, INT64_MAX, hex));
>>>> +        }
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("variables", std::move(variables));
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +// A request used in testing to get the details on all breakpoints that are
>>>> +// currently set in the target. This helps us to test "setBreakpoints" and
>>>> +// "setFunctionBreakpoints" requests to verify we have the correct set of
>>>> +// breakpoints currently set in LLDB.
>>>> +void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
>>>> +  llvm::json::Object response;
>>>> +  FillResponse(request, response);
>>>> +  llvm::json::Array response_breakpoints;
>>>> +  for (uint32_t i = 0; g_vsc.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
>>>> +    auto bp = g_vsc.target.GetBreakpointAtIndex(i);
>>>> +    AppendBreakpoint(bp, response_breakpoints);
>>>> +  }
>>>> +  llvm::json::Object body;
>>>> +  body.try_emplace("breakpoints", std::move(response_breakpoints));
>>>> +  response.try_emplace("body", std::move(body));
>>>> +  g_vsc.SendJSON(llvm::json::Value(std::move(response)));
>>>> +}
>>>> +
>>>> +const std::map<std::string, RequestCallback> &GetRequestHandlers() {
>>>> +#define REQUEST_CALLBACK(name)                                                 \
>>>> +  { #name, request_##name }
>>>> +  static std::map<std::string, RequestCallback> g_request_handlers = {
>>>> +      // VSCode Debug Adaptor requests
>>>> +      REQUEST_CALLBACK(attach),
>>>> +      REQUEST_CALLBACK(continue),
>>>> +      REQUEST_CALLBACK(configurationDone),
>>>> +      REQUEST_CALLBACK(disconnect),
>>>> +      REQUEST_CALLBACK(evaluate),
>>>> +      REQUEST_CALLBACK(exceptionInfo),
>>>> +      REQUEST_CALLBACK(initialize),
>>>> +      REQUEST_CALLBACK(launch),
>>>> +      REQUEST_CALLBACK(next),
>>>> +      REQUEST_CALLBACK(pause),
>>>> +      REQUEST_CALLBACK(scopes),
>>>> +      REQUEST_CALLBACK(setBreakpoints),
>>>> +      REQUEST_CALLBACK(setExceptionBreakpoints),
>>>> +      REQUEST_CALLBACK(setFunctionBreakpoints),
>>>> +      REQUEST_CALLBACK(setVariable),
>>>> +      REQUEST_CALLBACK(source),
>>>> +      REQUEST_CALLBACK(stackTrace),
>>>> +      REQUEST_CALLBACK(stepIn),
>>>> +      REQUEST_CALLBACK(stepOut),
>>>> +      REQUEST_CALLBACK(threads),
>>>> +      REQUEST_CALLBACK(variables),
>>>> +      // Testing requests
>>>> +      REQUEST_CALLBACK(_testGetTargetBreakpoints),
>>>> +  };
>>>> +#undef REQUEST_CALLBACK
>>>> +  return g_request_handlers;
>>>> +}
>>>> +  
>>>> +} // anonymous namespace
>>>> +
>>>> +int main(int argc, char *argv[]) {
>>>> +
>>>> +  // Initialize LLDB first before we do anything.
>>>> +  lldb::SBDebugger::Initialize();
>>>> +
>>>> +  if (argc == 2) {
>>>> +    const char *arg = argv[1];
>>>> +#if !defined(_WIN32)
>>>> +    if (strcmp(arg, "-g") == 0) {
>>>> +      printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid());
>>>> +      pause();
>>>> +    } else {
>>>> +#else
>>>> +    {
>>>> +#endif
>>>> +      int portno = atoi(arg);
>>>> +      printf("Listening on port %i...\n", portno);
>>>> +      int socket_fd = AcceptConnection(portno);
>>>> +      if (socket_fd >= 0) {
>>>> +        // We must open two FILE objects, one for reading and one for writing
>>>> +        // the FILE objects have a mutex in them that won't allow reading and
>>>> +        // writing to the socket stream.
>>>> +        g_vsc.in = fdopen(socket_fd, "r");
>>>> +        g_vsc.out = fdopen(socket_fd, "w");
>>>> +        if (g_vsc.in == nullptr || g_vsc.out == nullptr) {
>>>> +          if (g_vsc.log)
>>>> +            *g_vsc.log << "fdopen failed (" << strerror(errno) << ")"
>>>> +                       << std::endl;
>>>> +          exit(1);
>>>> +        }
>>>> +      } else {
>>>> +        exit(1);
>>>> +      }
>>>> +    }
>>>> +  }
>>>> +  auto request_handlers = GetRequestHandlers();
>>>> +  uint32_t packet_idx = 0;
>>>> +  while (true) {
>>>> +    std::string json = g_vsc.ReadJSON();
>>>> +    if (json.empty())
>>>> +      break;
>>>> +
>>>> +    llvm::StringRef json_sref(json);
>>>> +    llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
>>>> +    if (!json_value) {
>>>> +      auto error = json_value.takeError();
>>>> +      if (g_vsc.log) {
>>>> +        std::string error_str;
>>>> +        llvm::raw_string_ostream strm(error_str);
>>>> +        strm << error;
>>>> +        strm.flush();
>>>> +
>>>> +        *g_vsc.log << "error: failed to parse JSON: " << error_str << std::endl
>>>> +                   << json << std::endl;
>>>> +      }
>>>> +      return 1;
>>>> +    }
>>>> +
>>>> +    auto object = json_value->getAsObject();
>>>> +    if (!object) {
>>>> +      if (g_vsc.log)
>>>> +        *g_vsc.log << "error: json packet isn't a object" << std::endl;
>>>> +      return 1;
>>>> +    }
>>>> +
>>>> +    const auto packet_type = GetString(object, "type");
>>>> +    if (packet_type == "request") {
>>>> +      const auto command = GetString(object, "command");
>>>> +      auto handler_pos = request_handlers.find(command);
>>>> +      if (handler_pos != request_handlers.end()) {
>>>> +        handler_pos->second(*object);
>>>> +      } else {
>>>> +        if (g_vsc.log)
>>>> +          *g_vsc.log << "error: unhandled command \"" << command.data() << std::endl;
>>>> +        return 1;
>>>> +      }
>>>> +    }
>>>> +    ++packet_idx;
>>>> +  }
>>>> +
>>>> +  // We must terminate the debugger in a thread before the C++ destructor
>>>> +  // chain messes everything up.
>>>> +  lldb::SBDebugger::Terminate();
>>>> +  return 0;
>>>> +}
>>>> 
>>>> Added: lldb/trunk/tools/lldb-vscode/package.json
>>>> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/package.json?rev=339911&view=auto <http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-vscode/package.json?rev=339911&view=auto>
>>>> ==============================================================================
>>>> --- lldb/trunk/tools/lldb-vscode/package.json (added)
>>>> +++ lldb/trunk/tools/lldb-vscode/package.json Thu Aug 16 10:59:38 2018
>>>> @@ -0,0 +1,242 @@
>>>> +{
>>>> +	"name": "lldb-vscode",
>>>> +	"displayName": "LLDB native Debug stub",
>>>> +	"version": "0.1.0",
>>>> +	"publisher": "llvm.org <http://llvm.org/>",
>>>> +	"description": "Debug adapter for LLDB which uses a C++ tool to interface directly with LLDB.",
>>>> +	"author": {
>>>> +		"name": "Greg Clayton",
>>>> +		"email": "clayborg at gmail.com <mailto:clayborg at gmail.com>"
>>>> +	},
>>>> +	"license": "LLVM",
>>>> +	"keywords": [
>>>> +		"multi-root ready"
>>>> +	],
>>>> +	"engines": {
>>>> +		"vscode": "^1.18.0",
>>>> +		"node": "^7.9.0"
>>>> +	},
>>>> +	"icon": "images/lldb.png",
>>>> +	"categories": [
>>>> +		"Debuggers"
>>>> +	],
>>>> +	"private": true,
>>>> +	"devDependencies": {
>>>> +		"@types/node": "7.0.43",
>>>> +		"@types/mocha": "2.2.45",
>>>> +		"typescript": "2.6.2",
>>>> +		"mocha": "4.0.1",
>>>> +		"vscode": "1.1.10",
>>>> +		"vscode-debugadapter-testsupport": "1.25.0",
>>>> +		"tslint": "5.8.0",
>>>> +		"vsce": "1.35.0"
>>>> +	},
>>>> +	"contributes": {
>>>> +		"debuggers": [
>>>> +			{
>>>> +				"type": "lldb-vscode",
>>>> +				"label": "Native LLDB Debugger",
>>>> +				"enableBreakpointsFor": {
>>>> +					"languageIds": [
>>>> +						"ada",
>>>> +						"arm",
>>>> +						"asm",
>>>> +						"c",
>>>> +						"cpp",
>>>> +						"crystal",
>>>> +						"d",
>>>> +						"fortan",
>>>> +						"fortran-modern",
>>>> +						"nim",
>>>> +						"objective-c",
>>>> +						"objectpascal",
>>>> +						"pascal",
>>>> +						"rust",
>>>> +						"swift"
>>>> +					]
>>>> +				},
>>>> +				"program": "./bin/lldb-vscode",
>>>> +				"configurationAttributes": {
>>>> +					"launch": {
>>>> +						"required": [
>>>> +							"program"
>>>> +						],
>>>> +						"properties": {
>>>> +							"program": {
>>>> +								"type": "string",
>>>> +								"description": "Path to the program to debug."
>>>> +							},
>>>> +							"args": {
>>>> +								"type": [ "array", "string" ],
>>>> +								"description": "Program arguments.",
>>>> +								"default": []
>>>> +							},
>>>> +							"cwd": {
>>>> +								"type": "string",
>>>> +								"description": "Program working directory.",
>>>> +								"default": "${workspaceRoot}"
>>>> +							},
>>>> +							"env": {
>>>> +								"type": "array",
>>>> +								"description": "Additional environment variables.",
>>>> +								"default": []
>>>> +							},
>>>> +							"stopOnEntry": {
>>>> +								"type": "boolean",
>>>> +								"description": "Automatically stop after launch.",
>>>> +								"default": false
>>>> +							},
>>>> +							"disableASLR": {
>>>> +								"type": "boolean",
>>>> +								"description": "Enable or disable Address space layout randomization if the debugger supports it.",
>>>> +								"default": true
>>>> +							},
>>>> +							"disableSTDIO": {
>>>> +								"type": "boolean",
>>>> +								"description": "Don't retrieve STDIN, STDOUT and STDERR as the program is running.",
>>>> +								"default": false
>>>> +							},
>>>> +							"shellExpandArguments": {
>>>> +								"type": "boolean",
>>>> +								"description": "Expand program arguments as a shell would without actually launching the program in a shell.",
>>>> +								"default": false
>>>> +							},
>>>> +							"detachOnError": {
>>>> +								"type": "boolean",
>>>> +								"description": "Detach from the program.",
>>>> +								"default": false
>>>> +							},
>>>> +							"trace": {
>>>> +								"type": "boolean",
>>>> +								"description": "Enable logging of the Debug Adapter Protocol.",
>>>> +								"default": true
>>>> +							},
>>>> +							"sourcePath": {
>>>> +								"type": "string",
>>>> +								"description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths."
>>>> +							},
>>>> +							"sourceMap": {
>>>> +								"type": "array",
>>>> +								"description": "Specify an array of path remappings; each element must itself be a two element array containing a source and desination pathname. Overrides sourcePath.",
>>>> +								"default": []
>>>> +							},
>>>> +							"debuggerRoot": {
>>>> +								"type": "string",
>>>> +								"description": "Specify a working directory to set the debug adaptor to so relative object files can be located."
>>>> +							},
>>>> +							"initCommands": {
>>>> +									"type": "array",
>>>> +									"description": "Initialization commands executed upon debugger startup.",
>>>> +									"default": []
>>>> +							},
>>>> +							"preRunCommands": {
>>>> +									"type": "array",
>>>> +									"description": "Commands executed just before the program is launched.",
>>>> +									"default": []
>>>> +							},
>>>> +							"stopCommands": {
>>>> +									"type": "array",
>>>> +									"description": "Commands executed each time the program stops.",
>>>> +									"default": []
>>>> +							},
>>>> +							"exitCommands": {
>>>> +									"type": "array",
>>>> +									"description": "Commands executed at the end of debugging session.",
>>>> +									"default": []
>>>> +							}
>>>> +						}
>>>> +					},
>>>> +					"attach": {
>>>> +						"properties": {
>>>> +							"program": {
>>>> +								"type": "string",
>>>> +									"description": "Path to the program to attach to."
>>>> +							},
>>>> +							"pid": {
>>>> +								"type": [
>>>> +										"number",
>>>> +										"string"
>>>> +								],
>>>> +								"description": "System process ID to attach to."
>>>> +							},
>>>> +							"waitFor": {
>>>> +								"type": "boolean",
>>>> +								"description": "If set to true, then wait for the process to launch by looking for a process with a basename that matches `program`. No process ID needs to be specified when using this flag.",
>>>> +								"default": true
>>>> +							},
>>>> +							"trace": {
>>>> +								"type": "boolean",
>>>> +								"description": "Enable logging of the Debug Adapter Protocol.",
>>>> +								"default": true
>>>> +							},
>>>> +							"sourcePath": {
>>>> +								"type": "string",
>>>> +								"description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths."
>>>> +							},
>>>> +							"sourceMap": {
>>>> +								"type": "array",
>>>> +								"description": "Specify an array of path remappings; each element must itself be a two element array containing a source and desination pathname. Overrides sourcePath.",
>>>> +								"default": []
>>>> +							},
>>>> +							"debuggerRoot": {
>>>> +								"type": "string",
>>>> +								"description": "Specify a working directory to set the debug adaptor to so relative object files can be located."
>>>> +							},
>>>> +							"attachCommands": {
>>>> +								"type": "array",
>>>> +								"description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands may optionally create a new target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail.",
>>>> +								"default": []
>>>> +							},
>>>> +							"initCommands": {
>>>> +								"type": "array",
>>>> +								"description": "Initialization commands executed upon debugger startup.",
>>>> +								"default": []
>>>> +							},
>>>> +							"preRunCommands": {
>>>> +								"type": "array",
>>>> +								"description": "Commands executed just before the program is attached to.",
>>>> +								"default": []
>>>> +							},
>>>> +							"stopCommands": {
>>>> +								"type": "array",
>>>> +								"description": "Commands executed each time the program stops.",
>>>> +								"default": []
>>>> +							},
>>>> +							"exitCommands": {
>>>> +								"type": "array",
>>>> +									"description": "Commands executed at the end of debugging session.",
>>>> +									"default": []
>>>> +							}
>>>> +						}
>>>> +					}
>>>> +				},
>>>> +				"initialConfigurations": [
>>>> +					{
>>>> +						"type": "lldb-vscode",
>>>> +						"request": "launch",
>>>> +						"name": "Debug",
>>>> +						"program": "${workspaceRoot}/<your program>",
>>>> +						"args": [],
>>>> +						"env": [],
>>>> +						"cwd": "${workspaceRoot}"
>>>> +					}
>>>> +				],
>>>> +				"configurationSnippets": [
>>>> +					{
>>>> +						"label": "LLDB: Launch",
>>>> +						"description": "",
>>>> +						"body": {
>>>> +							"type": "lldb-vscode",
>>>> +							"request": "launch",
>>>> +							"name": "${2:Launch}",
>>>> +							"program": "^\"\\${workspaceRoot}/${1:<your program>}\"",
>>>> +							"args": [],
>>>> +							"env": [],
>>>> +							"cwd": "^\"\\${workspaceRoot}\""
>>>> +						}
>>>> +					}
>>>> +				]
>>>> +			}
>>>> +		]
>>>> +	}
>>>> +}
>>>> 
>>>> 
>>>> _______________________________________________
>>>> lldb-commits mailing list
>>>> lldb-commits at lists.llvm.org <mailto:lldb-commits at lists.llvm.org>
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits>
>>> 
>>> _______________________________________________
>>> lldb-commits mailing list
>>> lldb-commits at lists.llvm.org <mailto:lldb-commits at lists.llvm.org>
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits>
>> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20180817/72863fc1/attachment-0001.html>


More information about the lldb-commits mailing list