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

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Fri Aug 17 10:17:13 PDT 2018



> On Aug 17, 2018, at 10:15 AM, Greg Clayton <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
> 

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


More information about the lldb-commits mailing list