<div dir="ltr">On Wed, Mar 31, 2021 at 1:34 AM Stefan Gränitz <<a href="mailto:stefan.graenitz@gmail.com">stefan.graenitz@gmail.com</a>> wrote:<br>><br>> Hi David, thanks for working on it!<br>><br>> I ran the test suite on Linux and macOS with examples enabled and it worked well.<br><br>Did you modify an existing build directory that had already built the examples from some other invocation?<br><br>If you do these things:<br><br>1) enable examples in your CMakeCache.txt:<br> LLVM_BUILD_EXAMPLES:BOOL=ON<br> LLVM_INCLUDE_EXAMPLES:BOOL=ON<br>2) Delete any already built version of the jit binary:<br> build$ rm -f ./bin/LLJITWithRemoteDebugging<br>3) Undo ae217bf1f3277b8c14590a130ee5e63cc1664443 by making this change:<br><font face="monospace">diff --git llvm/test/CMakeLists.txt llvm/test/CMakeLists.txt<br>index 81107be862de..7c4fa2e9033a 100644<br>--- llvm/test/CMakeLists.txt<br>+++ llvm/test/CMakeLists.txt<br>@@ -158,11 +158,6 @@ if(LLVM_BUILD_EXAMPLES)<br>     Kaleidoscope-Ch7<br>     LLJITWithThinLTOSummaries<br>     )<br>-  if(CMAKE_HOST_UNIX)<br>-    list(APPEND LLVM_TEST_DEPENDS<br>-      LLJITWithRemoteDebugging<br>-      )<br>-  endif()<br>   if (NOT WIN32)<br>     list(APPEND LLVM_TEST_DEPENDS<br>       Bye</font><br><br>then run `ninja check-llvm-examples` (or make, etc - though perhaps ninja is part of the necessary repro steps, I guess - I haven't tried with make) - does it fail for you?<br><br>> Also, I didn't get a message from buildmaster for this. Do we have a bot for your setup and is it public?<br><br>Not sure - I guess probably not. We probably should have something building with the examples enabled.<br><br>><br>> On 30/03/2021 22:05, David Blaikie wrote:<br>><br>> This broke the build with examples enabled (LLVM_BUILD_EXAMPLES=ON) I think. My second attempt at fixing this is in ae217bf1f3277b8c14590a130ee5e63cc1664443<br>><br>> On Sun, Mar 28, 2021 at 8:25 AM Stefan Gränitz via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br>>><br>>><br>>> Author: Stefan Gränitz<br>>> Date: 2021-03-28T17:25:09+02:00<br>>> New Revision: 258f055ed93661900bc568350e09f467c0950486<br>>><br>>> URL: <a href="https://github.com/llvm/llvm-project/commit/258f055ed93661900bc568350e09f467c0950486">https://github.com/llvm/llvm-project/commit/258f055ed93661900bc568350e09f467c0950486</a><br>>> DIFF: <a href="https://github.com/llvm/llvm-project/commit/258f055ed93661900bc568350e09f467c0950486.diff">https://github.com/llvm/llvm-project/commit/258f055ed93661900bc568350e09f467c0950486.diff</a><br>>><br>>> LOG: [Orc][examples] Add LLJITWithRemoteDebugging example<br>>><br>>> Added:<br>>>     llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/CMakeLists.txt<br>>>     llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/LLJITWithRemoteDebugging.cpp<br>>>     llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.cpp<br>>>     llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.h<br>>>     llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1.c<br>>>     llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1_elf.ll<br>>>     llvm/test/Examples/OrcV2Examples/lljit-with-remote-debugging.test<br>>><br>>> Modified:<br>>>     llvm/examples/OrcV2Examples/CMakeLists.txt<br>>>     llvm/examples/OrcV2Examples/ExampleModules.h<br>>><br>>> Removed:<br>>><br>>><br>>><br>>> ################################################################################<br>>> diff  --git a/llvm/examples/OrcV2Examples/CMakeLists.txt b/llvm/examples/OrcV2Examples/CMakeLists.txt<br>>> index bed277e59e0b..f6a11d6f0ef2 100644<br>>> --- a/llvm/examples/OrcV2Examples/CMakeLists.txt<br>>> +++ b/llvm/examples/OrcV2Examples/CMakeLists.txt<br>>> @@ -12,3 +12,7 @@ add_subdirectory(OrcV2CBindingsAddObjectFile)<br>>>  add_subdirectory(OrcV2CBindingsBasicUsage)<br>>>  add_subdirectory(OrcV2CBindingsReflectProcessSymbols)<br>>>  add_subdirectory(OrcV2CBindingsRemovableCode)<br>>> +<br>>> +if(CMAKE_HOST_UNIX)<br>>> +  add_subdirectory(LLJITWithRemoteDebugging)<br>>> +endif()<br>>><br>>> diff  --git a/llvm/examples/OrcV2Examples/ExampleModules.h b/llvm/examples/OrcV2Examples/ExampleModules.h<br>>> index c88609fae769..53da756e15f7 100644<br>>> --- a/llvm/examples/OrcV2Examples/ExampleModules.h<br>>> +++ b/llvm/examples/OrcV2Examples/ExampleModules.h<br>>> @@ -52,4 +52,16 @@ parseExampleModule(llvm::StringRef Source, llvm::StringRef Name) {<br>>>    return createSMDiagnosticError(Err);<br>>>  }<br>>><br>>> +inline llvm::Expected<llvm::orc::ThreadSafeModule><br>>> +parseExampleModuleFromFile(llvm::StringRef FileName) {<br>>> +  using namespace llvm;<br>>> +  auto Ctx = std::make_unique<LLVMContext>();<br>>> +  SMDiagnostic Err;<br>>> +<br>>> +  if (auto M = parseIRFile(FileName, Err, *Ctx))<br>>> +    return orc::ThreadSafeModule(std::move(M), std::move(Ctx));<br>>> +<br>>> +  return createSMDiagnosticError(Err);<br>>> +}<br>>> +<br>>>  #endif // LLVM_EXAMPLES_ORCV2EXAMPLES_EXAMPLEMODULES_H<br>>><br>>> diff  --git a/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/CMakeLists.txt b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/CMakeLists.txt<br>>> new file mode 100644<br>>> index 000000000000..b93dd4924b05<br>>> --- /dev/null<br>>> +++ b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/CMakeLists.txt<br>>> @@ -0,0 +1,18 @@<br>>> +set(LLVM_LINK_COMPONENTS<br>>> +  Core<br>>> +  ExecutionEngine<br>>> +  IRReader<br>>> +  JITLink<br>>> +  OrcJIT<br>>> +  OrcTargetProcess<br>>> +  Support<br>>> +  nativecodegen<br>>> +  )<br>>> +<br>>> +add_llvm_example(LLJITWithRemoteDebugging<br>>> +  LLJITWithRemoteDebugging.cpp<br>>> +  RemoteJITUtils.cpp<br>>> +<br>>> +  DEPENDS<br>>> +    llvm-jitlink-executor<br>>> +  )<br>>><br>>> diff  --git a/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/LLJITWithRemoteDebugging.cpp b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/LLJITWithRemoteDebugging.cpp<br>>> new file mode 100644<br>>> index 000000000000..6da30f608206<br>>> --- /dev/null<br>>> +++ b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/LLJITWithRemoteDebugging.cpp<br>>> @@ -0,0 +1,258 @@<br>>> +//===--- LLJITWithRemoteDebugging.cpp - LLJIT targeting a child process ---===//<br>>> +//<br>>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>>> +// See <a href="https://llvm.org/LICENSE.txt">https://llvm.org/LICENSE.txt</a> for license information.<br>>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>>> +//<br>>> +//===----------------------------------------------------------------------===//<br>>> +//<br>>> +// This example shows how to use LLJIT and JITLink for out-of-process execution<br>>> +// with debug support.  A few notes beforehand:<br>>> +//<br>>> +//  * Debuggers must implement the GDB JIT interface (gdb, udb, lldb 12+).<br>>> +//  * Debug support is currently limited to ELF on x86-64 platforms that run<br>>> +//    Unix-like systems.<br>>> +//  * There is a test for this example and it ships an IR file that is prepared<br>>> +//    for the instructions below.<br>>> +//<br>>> +//<br>>> +// The following command line session provides a complete walkthrough of the<br>>> +// feature using LLDB 12:<br>>> +//<br>>> +// [Terminal 1] Prepare a debuggable out-of-process JIT session:<br>>> +//<br>>> +//    > cd llvm-project/build<br>>> +//    > ninja LLJITWithRemoteDebugging llvm-jitlink-executor<br>>> +//    > cp ../llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1_elf.ll .<br>>> +//    > bin/LLJITWithRemoteDebugging --wait-for-debugger argc_sub1_elf.ll<br>>> +//    Found out-of-process executor: bin/llvm-jitlink-executor<br>>> +//    Launched executor in subprocess: 65535<br>>> +//    Attach a debugger and press any key to continue.<br>>> +//<br>>> +//<br>>> +// [Terminal 2] Attach a debugger to the child process:<br>>> +//<br>>> +//    (lldb) log enable lldb jit<br>>> +//    (lldb) settings set plugin.jit-loader.gdb.enable on<br>>> +//    (lldb) settings set target.source-map Inputs/ \<br>>> +//             /path/to/llvm-project/llvm/test/Examples/OrcV2Examples/Inputs/<br>>> +//    (lldb) attach -p 65535<br>>> +//     JITLoaderGDB::SetJITBreakpoint looking for JIT register hook<br>>> +//     JITLoaderGDB::SetJITBreakpoint setting JIT breakpoint<br>>> +//    Process 65535 stopped<br>>> +//    (lldb) b sub1<br>>> +//    Breakpoint 1: no locations (pending).<br>>> +//    WARNING:  Unable to resolve breakpoint to any actual locations.<br>>> +//    (lldb) c<br>>> +//    Process 65535 resuming<br>>> +//<br>>> +//<br>>> +// [Terminal 1] Press a key to start code generation and execution:<br>>> +//<br>>> +//    Parsed input IR code from: argc_sub1_elf.ll<br>>> +//    Initialized LLJIT for remote executor<br>>> +//    Running: argc_sub1_elf.ll<br>>> +//<br>>> +//<br>>> +// [Terminal 2] Breakpoint hits; we change the argc value from 1 to 42:<br>>> +//<br>>> +//    (lldb)  JITLoaderGDB::JITDebugBreakpointHit hit JIT breakpoint<br>>> +//     JITLoaderGDB::ReadJITDescriptorImpl registering JIT entry at 0x106b34000<br>>> +//    1 location added to breakpoint 1<br>>> +//    Process 65535 stopped<br>>> +//    * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1<br>>> +//        frame #0: JIT(0x106b34000)`sub1(x=1) at argc_sub1.c:1:28<br>>> +//    -> 1     int sub1(int x) { return x - 1; }<br>>> +//       2     int main(int argc, char **argv) { return sub1(argc); }<br>>> +//    (lldb) p x<br>>> +//    (int) $0 = 1<br>>> +//    (lldb) expr x = 42<br>>> +//    (int) $1 = 42<br>>> +//    (lldb) c<br>>> +//<br>>> +//<br>>> +// [Terminal 1] Example output reflects the modified value:<br>>> +//<br>>> +//    Exit code: 41<br>>> +//<br>>> +//===----------------------------------------------------------------------===//<br>>> +<br>>> +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"<br>>> +#include "llvm/ExecutionEngine/Orc/LLJIT.h"<br>>> +#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"<br>>> +#include "llvm/Support/CommandLine.h"<br>>> +#include "llvm/Support/Error.h"<br>>> +#include "llvm/Support/FormatVariadic.h"<br>>> +#include "llvm/Support/InitLLVM.h"<br>>> +#include "llvm/Support/TargetSelect.h"<br>>> +#include "llvm/Support/raw_ostream.h"<br>>> +<br>>> +#include "../ExampleModules.h"<br>>> +#include "RemoteJITUtils.h"<br>>> +<br>>> +#include <memory><br>>> +#include <string><br>>> +<br>>> +using namespace llvm;<br>>> +using namespace llvm::orc;<br>>> +<br>>> +// The LLVM IR file to run.<br>>> +static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,<br>>> +                                        cl::desc("<input files>"));<br>>> +<br>>> +// Command line arguments to pass to the JITed main function.<br>>> +static cl::list<std::string> InputArgv("args", cl::Positional,<br>>> +                                       cl::desc("<program arguments>..."),<br>>> +                                       cl::ZeroOrMore, cl::PositionalEatsArgs);<br>>> +<br>>> +// Given paths must exist on the remote target.<br>>> +static cl::list<std::string><br>>> +    Dylibs("dlopen", cl::desc("Dynamic libraries to load before linking"),<br>>> +           cl::value_desc("filename"), cl::ZeroOrMore);<br>>> +<br>>> +// File path of the executable to launch for execution in a child process.<br>>> +// Inter-process communication will go through stdin/stdout pipes.<br>>> +static cl::opt<std::string><br>>> +    OOPExecutor("executor", cl::desc("Set the out-of-process executor"),<br>>> +                cl::value_desc("filename"));<br>>> +<br>>> +// Network address of a running executor process that we can connected through a<br>>> +// TCP socket. It may run locally or on a remote machine.<br>>> +static cl::opt<std::string> OOPExecutorConnect(<br>>> +    "connect",<br>>> +    cl::desc("Connect to an out-of-process executor through a TCP socket"),<br>>> +    cl::value_desc("<hostname>:<port>"));<br>>> +<br>>> +// Give the user a chance to connect a debugger. Once we connected the executor<br>>> +// process, wait for the user to press a key (and print out its PID if it's a<br>>> +// child process).<br>>> +static cl::opt<bool><br>>> +    WaitForDebugger("wait-for-debugger",<br>>> +                    cl::desc("Wait for user input before entering JITed code"),<br>>> +                    cl::init(false));<br>>> +<br>>> +ExitOnError ExitOnErr;<br>>> +<br>>> +static std::unique_ptr<JITLinkExecutor> connectExecutor(const char *Argv0,<br>>> +                                                        ExecutionSession &ES) {<br>>> +  // Connect to a running out-of-process executor through a TCP socket.<br>>> +  if (!OOPExecutorConnect.empty()) {<br>>> +    std::unique_ptr<TCPSocketJITLinkExecutor> Exec =<br>>> +        ExitOnErr(JITLinkExecutor::ConnectTCPSocket(OOPExecutorConnect, ES));<br>>> +<br>>> +    outs() << "Connected to executor at " << OOPExecutorConnect << "\n";<br>>> +    if (WaitForDebugger) {<br>>> +      outs() << "Attach a debugger and press any key to continue.\n";<br>>> +      fflush(stdin);<br>>> +      getchar();<br>>> +    }<br>>> +<br>>> +    return std::move(Exec);<br>>> +  }<br>>> +<br>>> +  // Launch a out-of-process executor locally in a child process.<br>>> +  std::unique_ptr<ChildProcessJITLinkExecutor> Exec = ExitOnErr(<br>>> +      OOPExecutor.empty() ? JITLinkExecutor::FindLocal(Argv0)<br>>> +                          : JITLinkExecutor::CreateLocal(OOPExecutor));<br>>> +<br>>> +  outs() << "Found out-of-process executor: " << Exec->getPath() << "\n";<br>>> +<br>>> +  ExitOnErr(Exec->launch(ES));<br>>> +  if (WaitForDebugger) {<br>>> +    outs() << "Launched executor in subprocess: " << Exec->getPID() << "\n"<br>>> +           << "Attach a debugger and press any key to continue.\n";<br>>> +    fflush(stdin);<br>>> +    getchar();<br>>> +  }<br>>> +<br>>> +  return std::move(Exec);<br>>> +}<br>>> +<br>>> +int main(int argc, char *argv[]) {<br>>> +  InitLLVM X(argc, argv);<br>>> +<br>>> +  InitializeNativeTarget();<br>>> +  InitializeNativeTargetAsmPrinter();<br>>> +<br>>> +  ExitOnErr.setBanner(std::string(argv[0]) + ": ");<br>>> +  cl::ParseCommandLineOptions(argc, argv, "LLJITWithRemoteDebugging");<br>>> +<br>>> +  auto ES = std::make_unique<ExecutionSession>();<br>>> +  ES->setErrorReporter([&](Error Err) { ExitOnErr(std::move(Err)); });<br>>> +<br>>> +  // Launch/connect the out-of-process executor.<br>>> +  std::unique_ptr<JITLinkExecutor> Executor = connectExecutor(argv[0], *ES);<br>>> +<br>>> +  // Load the given IR files.<br>>> +  std::vector<ThreadSafeModule> TSMs;<br>>> +  for (const std::string &Path : InputFiles) {<br>>> +    outs() << "Parsing input IR code from: " << Path << "\n";<br>>> +    TSMs.push_back(ExitOnErr(parseExampleModuleFromFile(Path)));<br>>> +  }<br>>> +<br>>> +  StringRef TT;<br>>> +  StringRef MainModuleName;<br>>> +  TSMs.front().withModuleDo([&MainModuleName, &TT](Module &M) {<br>>> +    MainModuleName = M.getName();<br>>> +    TT = M.getTargetTriple();<br>>> +  });<br>>> +<br>>> +  for (const ThreadSafeModule &TSM : TSMs)<br>>> +    ExitOnErr(TSM.withModuleDo([TT, MainModuleName](Module &M) -> Error {<br>>> +      if (M.getTargetTriple() != TT)<br>>> +        return make_error<StringError>(<br>>> +            formatv("Different target triples in input files:\n"<br>>> +                    "  '{0}' in '{1}'\n  '{2}' in '{3}'",<br>>> +                    TT, MainModuleName, M.getTargetTriple(), M.getName()),<br>>> +            inconvertibleErrorCode());<br>>> +      return Error::success();<br>>> +    }));<br>>> +<br>>> +  // Create a target machine that matches the input triple.<br>>> +  JITTargetMachineBuilder JTMB((Triple(TT)));<br>>> +  JTMB.setCodeModel(CodeModel::Small);<br>>> +  JTMB.setRelocationModel(Reloc::PIC_);<br>>> +<br>>> +  // Create LLJIT and destroy it before disconnecting the target process.<br>>> +  {<br>>> +    outs() << "Initializing LLJIT for remote executor\n";<br>>> +    auto J = ExitOnErr(LLJITBuilder()<br>>> +                           .setExecutionSession(std::move(ES))<br>>> +                           .setJITTargetMachineBuilder(std::move(JTMB))<br>>> +                           .setObjectLinkingLayerCreator(std::ref(*Executor))<br>>> +                           .create());<br>>> +<br>>> +    // Add plugin for debug support.<br>>> +    ExitOnErr(Executor->addDebugSupport(J->getObjLinkingLayer()));<br>>> +<br>>> +    // Load required shared libraries on the remote target and add a generator<br>>> +    // for each of it, so the compiler can lookup their symbols.<br>>> +    for (const std::string &Path : Dylibs)<br>>> +      J->getMainJITDylib().addGenerator(ExitOnErr(Executor->loadDylib(Path)));<br>>> +<br>>> +    // Add the loaded IR module to the JIT. This will set up symbol tables and<br>>> +    // prepare for materialization.<br>>> +    for (ThreadSafeModule &TSM : TSMs)<br>>> +      ExitOnErr(J->addIRModule(std::move(TSM)));<br>>> +<br>>> +    // The example uses a non-lazy JIT for simplicity. Thus, looking up the main<br>>> +    // function will materialize all reachable code. It also triggers debug<br>>> +    // registration in the remote target process.<br>>> +    JITEvaluatedSymbol MainFn = ExitOnErr(J->lookup("main"));<br>>> +<br>>> +    outs() << "Running: main(";<br>>> +    int Pos = 0;<br>>> +    for (const std::string &Arg : InputArgv)<br>>> +      outs() << (Pos++ == 0 ? "" : ", ") << Arg;<br>>> +    outs() << ")\n";<br>>> +<br>>> +    // Execute the code in the remote target process and dump the result. With<br>>> +    // the debugger attached to the target, it should be possible to inspect the<br>>> +    // JITed code as if it was compiled statically.<br>>> +    int Result = ExitOnErr(Executor->runAsMain(MainFn, InputArgv));<br>>> +    outs() << "Exit code: " << Result << "\n";<br>>> +  }<br>>> +<br>>> +  ExitOnErr(Executor->disconnect());<br>>> +  return 0;<br>>> +}<br>>><br>>> diff  --git a/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.cpp b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.cpp<br>>> new file mode 100644<br>>> index 000000000000..abce14de0fe0<br>>> --- /dev/null<br>>> +++ b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.cpp<br>>> @@ -0,0 +1,347 @@<br>>> +//===-- RemoteJITUtils.cpp - Utilities for remote-JITing --------*- C++ -*-===//<br>>> +//<br>>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>>> +// See <a href="https://llvm.org/LICENSE.txt">https://llvm.org/LICENSE.txt</a> for license information.<br>>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>>> +//<br>>> +//===----------------------------------------------------------------------===//<br>>> +<br>>> +#include "RemoteJITUtils.h"<br>>> +<br>>> +#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"<br>>> +#include "llvm/ExecutionEngine/Orc/OrcRPCTargetProcessControl.h"<br>>> +#include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"<br>>> +#include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"<br>>> +#include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"<br>>> +#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"<br>>> +#include "llvm/Support/FileSystem.h"<br>>> +#include "llvm/Support/Path.h"<br>>> +#include "llvm/Support/ToolOutputFile.h"<br>>> +<br>>> +#ifdef LLVM_ON_UNIX<br>>> +#include <netdb.h><br>>> +#include <netinet/in.h><br>>> +#include <sys/socket.h><br>>> +#include <unistd.h><br>>> +#endif // LLVM_ON_UNIX<br>>> +<br>>> +using namespace llvm;<br>>> +using namespace llvm::orc;<br>>> +<br>>> +namespace llvm {<br>>> +namespace orc {<br>>> +<br>>> +class RemoteTargetProcessControl<br>>> +    : public OrcRPCTargetProcessControlBase<<br>>> +          shared::MultiThreadedRPCEndpoint<JITLinkExecutor::RPCChannel>> {<br>>> +public:<br>>> +  using RPCChannel = JITLinkExecutor::RPCChannel;<br>>> +  using RPCEndpoint = shared::MultiThreadedRPCEndpoint<RPCChannel>;<br>>> +<br>>> +private:<br>>> +  using ThisT = RemoteTargetProcessControl;<br>>> +  using BaseT = OrcRPCTargetProcessControlBase<RPCEndpoint>;<br>>> +  using MemoryAccess = OrcRPCTPCMemoryAccess<ThisT>;<br>>> +  using MemoryManager = OrcRPCTPCJITLinkMemoryManager<ThisT>;<br>>> +<br>>> +public:<br>>> +  using BaseT::initializeORCRPCTPCBase;<br>>> +<br>>> +  RemoteTargetProcessControl(ExecutionSession &ES,<br>>> +                             std::unique_ptr<RPCChannel> Channel,<br>>> +                             std::unique_ptr<RPCEndpoint> Endpoint);<br>>> +<br>>> +  void initializeMemoryManagement();<br>>> +  Error disconnect() override;<br>>> +<br>>> +private:<br>>> +  std::unique_ptr<RPCChannel> Channel;<br>>> +  std::unique_ptr<RPCEndpoint> Endpoint;<br>>> +  std::unique_ptr<MemoryAccess> OwnedMemAccess;<br>>> +  std::unique_ptr<MemoryManager> OwnedMemMgr;<br>>> +  std::atomic<bool> Finished{false};<br>>> +  std::thread ListenerThread;<br>>> +};<br>>> +<br>>> +RemoteTargetProcessControl::RemoteTargetProcessControl(<br>>> +    ExecutionSession &ES, std::unique_ptr<RPCChannel> Channel,<br>>> +    std::unique_ptr<RPCEndpoint> Endpoint)<br>>> +    : BaseT(ES.getSymbolStringPool(), *Endpoint,<br>>> +            [&ES](Error Err) { ES.reportError(std::move(Err)); }),<br>>> +      Channel(std::move(Channel)), Endpoint(std::move(Endpoint)) {<br>>> +<br>>> +  ListenerThread = std::thread([&]() {<br>>> +    while (!Finished) {<br>>> +      if (auto Err = this->Endpoint->handleOne()) {<br>>> +        reportError(std::move(Err));<br>>> +        return;<br>>> +      }<br>>> +    }<br>>> +  });<br>>> +}<br>>> +<br>>> +void RemoteTargetProcessControl::initializeMemoryManagement() {<br>>> +  OwnedMemAccess = std::make_unique<MemoryAccess>(*this);<br>>> +  OwnedMemMgr = std::make_unique<MemoryManager>(*this);<br>>> +<br>>> +  // Base class needs non-owning access.<br>>> +  MemAccess = OwnedMemAccess.get();<br>>> +  MemMgr = OwnedMemMgr.get();<br>>> +}<br>>> +<br>>> +Error RemoteTargetProcessControl::disconnect() {<br>>> +  std::promise<MSVCPError> P;<br>>> +  auto F = P.get_future();<br>>> +  auto Err = closeConnection([&](Error Err) -> Error {<br>>> +    P.set_value(std::move(Err));<br>>> +    Finished = true;<br>>> +    return Error::success();<br>>> +  });<br>>> +  ListenerThread.join();<br>>> +  return joinErrors(std::move(Err), F.get());<br>>> +}<br>>> +<br>>> +} // namespace orc<br>>> +} // namespace llvm<br>>> +<br>>> +JITLinkExecutor::JITLinkExecutor() = default;<br>>> +JITLinkExecutor::~JITLinkExecutor() = default;<br>>> +<br>>> +Expected<std::unique_ptr<ObjectLayer>><br>>> +JITLinkExecutor::operator()(ExecutionSession &ES, const Triple &TT) {<br>>> +  return std::make_unique<ObjectLinkingLayer>(ES, TPC->getMemMgr());<br>>> +}<br>>> +<br>>> +Error JITLinkExecutor::addDebugSupport(ObjectLayer &ObjLayer) {<br>>> +  auto Registrar = createJITLoaderGDBRegistrar(*TPC);<br>>> +  if (!Registrar)<br>>> +    return Registrar.takeError();<br>>> +<br>>> +  cast<ObjectLinkingLayer>(&ObjLayer)->addPlugin(<br>>> +      std::make_unique<DebugObjectManagerPlugin>(ObjLayer.getExecutionSession(),<br>>> +                                                 std::move(*Registrar)));<br>>> +<br>>> +  return Error::success();<br>>> +}<br>>> +<br>>> +Expected<std::unique_ptr<DefinitionGenerator>><br>>> +JITLinkExecutor::loadDylib(StringRef RemotePath) {<br>>> +  if (auto Handle = TPC->loadDylib(RemotePath.data()))<br>>> +    return std::make_unique<TPCDynamicLibrarySearchGenerator>(*TPC, *Handle);<br>>> +  else<br>>> +    return Handle.takeError();<br>>> +}<br>>> +<br>>> +Expected<int> JITLinkExecutor::runAsMain(JITEvaluatedSymbol MainSym,<br>>> +                                         ArrayRef<std::string> Args) {<br>>> +  return TPC->runAsMain(MainSym.getAddress(), Args);<br>>> +}<br>>> +<br>>> +Error JITLinkExecutor::disconnect() { return TPC->disconnect(); }<br>>> +<br>>> +static std::string defaultPath(const char *HostArgv0, StringRef ExecutorName) {<br>>> +  // This just needs to be some symbol in the binary; C++ doesn't<br>>> +  // allow taking the address of ::main however.<br>>> +  void *P = (void *)(intptr_t)defaultPath;<br>>> +  SmallString<256> FullName(sys::fs::getMainExecutable(HostArgv0, P));<br>>> +  sys::path::remove_filename(FullName);<br>>> +  sys::path::append(FullName, ExecutorName);<br>>> +  return FullName.str().str();<br>>> +}<br>>> +<br>>> +Expected<std::unique_ptr<ChildProcessJITLinkExecutor>><br>>> +JITLinkExecutor::FindLocal(const char *HostArgv) {<br>>> +  std::string BestGuess = defaultPath(HostArgv, "llvm-jitlink-executor");<br>>> +  auto Executor = CreateLocal(BestGuess);<br>>> +  if (!Executor) {<br>>> +    consumeError(Executor.takeError());<br>>> +    return make_error<StringError>(<br>>> +        formatv("Unable to find usable executor: {0}", BestGuess),<br>>> +        inconvertibleErrorCode());<br>>> +  }<br>>> +  return Executor;<br>>> +}<br>>> +<br>>> +Expected<std::unique_ptr<ChildProcessJITLinkExecutor>><br>>> +JITLinkExecutor::CreateLocal(std::string ExecutablePath) {<br>>> +  if (!sys::fs::can_execute(ExecutablePath))<br>>> +    return make_error<StringError>(<br>>> +        formatv("Specified executor invalid: {0}", ExecutablePath),<br>>> +        inconvertibleErrorCode());<br>>> +  return std::unique_ptr<ChildProcessJITLinkExecutor>(<br>>> +      new ChildProcessJITLinkExecutor(std::move(ExecutablePath)));<br>>> +}<br>>> +<br>>> +TCPSocketJITLinkExecutor::TCPSocketJITLinkExecutor(<br>>> +    std::unique_ptr<RemoteTargetProcessControl> TPC) {<br>>> +  this->TPC = std::move(TPC);<br>>> +}<br>>> +<br>>> +#ifndef LLVM_ON_UNIX<br>>> +<br>>> +// FIXME: Add support for Windows.<br>>> +Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) {<br>>> +  return make_error<StringError>(<br>>> +      "Remote JITing not yet supported on non-unix platforms",<br>>> +      inconvertibleErrorCode());<br>>> +}<br>>> +<br>>> +// FIXME: Add support for Windows.<br>>> +Expected<std::unique_ptr<TCPSocketJITLinkExecutor>><br>>> +JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress,<br>>> +                                  ExecutionSession &ES) {<br>>> +  return make_error<StringError>(<br>>> +      "Remote JITing not yet supported on non-unix platforms",<br>>> +      inconvertibleErrorCode());<br>>> +}<br>>> +<br>>> +#else<br>>> +<br>>> +Error ChildProcessJITLinkExecutor::launch(ExecutionSession &ES) {<br>>> +  constexpr int ReadEnd = 0;<br>>> +  constexpr int WriteEnd = 1;<br>>> +<br>>> +  // Pipe FDs.<br>>> +  int ToExecutor[2];<br>>> +  int FromExecutor[2];<br>>> +<br>>> +  // Create pipes to/from the executor..<br>>> +  if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)<br>>> +    return make_error<StringError>("Unable to create pipe for executor",<br>>> +                                   inconvertibleErrorCode());<br>>> +<br>>> +  ProcessID = fork();<br>>> +  if (ProcessID == 0) {<br>>> +    // In the child...<br>>> +<br>>> +    // Close the parent ends of the pipes<br>>> +    close(ToExecutor[WriteEnd]);<br>>> +    close(FromExecutor[ReadEnd]);<br>>> +<br>>> +    // Execute the child process.<br>>> +    std::unique_ptr<char[]> ExecPath, FDSpecifier;<br>>> +    {<br>>> +      ExecPath = std::make_unique<char[]>(ExecutablePath.size() + 1);<br>>> +      strcpy(ExecPath.get(), ExecutablePath.data());<br>>> +<br>>> +      std::string FDSpecifierStr("filedescs=");<br>>> +      FDSpecifierStr += utostr(ToExecutor[ReadEnd]);<br>>> +      FDSpecifierStr += ',';<br>>> +      FDSpecifierStr += utostr(FromExecutor[WriteEnd]);<br>>> +      FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);<br>>> +      strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());<br>>> +    }<br>>> +<br>>> +    char *const Args[] = {ExecPath.get(), FDSpecifier.get(), nullptr};<br>>> +    int RC = execvp(ExecPath.get(), Args);<br>>> +    if (RC != 0)<br>>> +      return make_error<StringError>(<br>>> +          "Unable to launch out-of-process executor '" + ExecutablePath + "'\n",<br>>> +          inconvertibleErrorCode());<br>>> +<br>>> +    llvm_unreachable("Fork won't return in success case");<br>>> +  }<br>>> +  // else we're the parent...<br>>> +<br>>> +  // Close the child ends of the pipes<br>>> +  close(ToExecutor[ReadEnd]);<br>>> +  close(FromExecutor[WriteEnd]);<br>>> +<br>>> +  auto Channel =<br>>> +      std::make_unique<RPCChannel>(FromExecutor[ReadEnd], ToExecutor[WriteEnd]);<br>>> +  auto Endpoint =<br>>> +      std::make_unique<RemoteTargetProcessControl::RPCEndpoint>(*Channel, true);<br>>> +<br>>> +  TPC = std::make_unique<RemoteTargetProcessControl>(ES, std::move(Channel),<br>>> +                                                     std::move(Endpoint));<br>>> +<br>>> +  if (auto Err = TPC->initializeORCRPCTPCBase())<br>>> +    return joinErrors(std::move(Err), TPC->disconnect());<br>>> +<br>>> +  TPC->initializeMemoryManagement();<br>>> +<br>>> +  shared::registerStringError<RPCChannel>();<br>>> +  return Error::success();<br>>> +}<br>>> +<br>>> +static Expected<int> connectTCPSocketImpl(std::string Host,<br>>> +                                          std::string PortStr) {<br>>> +  addrinfo *AI;<br>>> +  addrinfo Hints{};<br>>> +  Hints.ai_family = AF_INET;<br>>> +  Hints.ai_socktype = SOCK_STREAM;<br>>> +  Hints.ai_flags = AI_NUMERICSERV;<br>>> +<br>>> +  if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))<br>>> +    return make_error<StringError>(<br>>> +        formatv("address resolution failed ({0})", gai_strerror(EC)),<br>>> +        inconvertibleErrorCode());<br>>> +<br>>> +  // Cycle through the returned addrinfo structures and connect to the first<br>>> +  // reachable endpoint.<br>>> +  int SockFD;<br>>> +  addrinfo *Server;<br>>> +  for (Server = AI; Server != nullptr; Server = Server->ai_next) {<br>>> +    // If socket fails, maybe it's because the address family is not supported.<br>>> +    // Skip to the next addrinfo structure.<br>>> +    if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)<br>>> +      continue;<br>>> +<br>>> +    // If connect works, we exit the loop with a working socket.<br>>> +    if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)<br>>> +      break;<br>>> +<br>>> +    close(SockFD);<br>>> +  }<br>>> +  freeaddrinfo(AI);<br>>> +<br>>> +  // Did we reach the end of the loop without connecting to a valid endpoint?<br>>> +  if (Server == nullptr)<br>>> +    return make_error<StringError>("invalid hostname",<br>>> +                                   inconvertibleErrorCode());<br>>> +<br>>> +  return SockFD;<br>>> +}<br>>> +<br>>> +Expected<std::unique_ptr<TCPSocketJITLinkExecutor>><br>>> +JITLinkExecutor::ConnectTCPSocket(StringRef NetworkAddress,<br>>> +                                  ExecutionSession &ES) {<br>>> +  auto CreateErr = [NetworkAddress](StringRef Details) {<br>>> +    return make_error<StringError>(<br>>> +        formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,<br>>> +                Details),<br>>> +        inconvertibleErrorCode());<br>>> +  };<br>>> +<br>>> +  StringRef Host, PortStr;<br>>> +  std::tie(Host, PortStr) = NetworkAddress.split(':');<br>>> +  if (Host.empty())<br>>> +    return CreateErr("host name cannot be empty");<br>>> +  if (PortStr.empty())<br>>> +    return CreateErr("port cannot be empty");<br>>> +  int Port = 0;<br>>> +  if (PortStr.getAsInteger(10, Port))<br>>> +    return CreateErr("port number is not a valid integer");<br>>> +<br>>> +  Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());<br>>> +  if (!SockFD)<br>>> +    return CreateErr(toString(SockFD.takeError()));<br>>> +<br>>> +  auto Channel = std::make_unique<RPCChannel>(*SockFD, *SockFD);<br>>> +  auto Endpoint =<br>>> +      std::make_unique<RemoteTargetProcessControl::RPCEndpoint>(*Channel, true);<br>>> +<br>>> +  auto TPC = std::make_unique<RemoteTargetProcessControl>(<br>>> +      ES, std::move(Channel), std::move(Endpoint));<br>>> +<br>>> +  if (auto Err = TPC->initializeORCRPCTPCBase())<br>>> +    return joinErrors(std::move(Err), TPC->disconnect());<br>>> +<br>>> +  TPC->initializeMemoryManagement();<br>>> +  shared::registerStringError<RPCChannel>();<br>>> +<br>>> +  return std::unique_ptr<TCPSocketJITLinkExecutor>(<br>>> +      new TCPSocketJITLinkExecutor(std::move(TPC)));<br>>> +}<br>>> +<br>>> +#endif<br>>><br>>> diff  --git a/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.h b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.h<br>>> new file mode 100644<br>>> index 000000000000..e629c0e036f5<br>>> --- /dev/null<br>>> +++ b/llvm/examples/OrcV2Examples/LLJITWithRemoteDebugging/RemoteJITUtils.h<br>>> @@ -0,0 +1,111 @@<br>>> +//===-- RemoteJITUtils.h - Utilities for remote-JITing ----------*- C++ -*-===//<br>>> +//<br>>> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.<br>>> +// See <a href="https://llvm.org/LICENSE.txt">https://llvm.org/LICENSE.txt</a> for license information.<br>>> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception<br>>> +//<br>>> +//===----------------------------------------------------------------------===//<br>>> +//<br>>> +// Utilities for TargetProcessControl-based remote JITing with Orc and JITLink.<br>>> +//<br>>> +//===----------------------------------------------------------------------===//<br>>> +<br>>> +#ifndef LLVM_EXAMPLES_ORCV2EXAMPLES_LLJITWITHREMOTEDEBUGGING_REMOTEJITUTILS_H<br>>> +#define LLVM_EXAMPLES_ORCV2EXAMPLES_LLJITWITHREMOTEDEBUGGING_REMOTEJITUTILS_H<br>>> +<br>>> +#include "llvm/ADT/ArrayRef.h"<br>>> +#include "llvm/ADT/StringRef.h"<br>>> +#include "llvm/ADT/Triple.h"<br>>> +#include "llvm/ExecutionEngine/JITSymbol.h"<br>>> +#include "llvm/ExecutionEngine/Orc/Core.h"<br>>> +#include "llvm/ExecutionEngine/Orc/Layer.h"<br>>> +#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"<br>>> +#include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"<br>>> +#include "llvm/Support/Error.h"<br>>> +<br>>> +#include <memory><br>>> +#include <string><br>>> +<br>>> +#if !defined(_MSC_VER) && !defined(__MINGW32__)<br>>> +#include <unistd.h><br>>> +#else<br>>> +#include <io.h><br>>> +#endif<br>>> +<br>>> +namespace llvm {<br>>> +namespace orc {<br>>> +<br>>> +class ChildProcessJITLinkExecutor;<br>>> +class RemoteTargetProcessControl;<br>>> +class TCPSocketJITLinkExecutor;<br>>> +<br>>> +class JITLinkExecutor {<br>>> +public:<br>>> +  using RPCChannel = shared::FDRawByteChannel;<br>>> +<br>>> +  /// Create a JITLinkExecutor for the given exectuable on disk.<br>>> +  static Expected<std::unique_ptr<ChildProcessJITLinkExecutor>><br>>> +  CreateLocal(std::string ExecutablePath);<br>>> +<br>>> +  /// Find the default exectuable on disk and create a JITLinkExecutor for it.<br>>> +  static Expected<std::unique_ptr<ChildProcessJITLinkExecutor>><br>>> +  FindLocal(const char *JITArgv0);<br>>> +<br>>> +  /// Create a JITLinkExecutor that connects to the given network address<br>>> +  /// through a TCP socket. A valid NetworkAddress provides hostname and port,<br>>> +  /// e.g. localhost:20000.<br>>> +  static Expected<std::unique_ptr<TCPSocketJITLinkExecutor>><br>>> +  ConnectTCPSocket(StringRef NetworkAddress, ExecutionSession &ES);<br>>> +<br>>> +  // Implement ObjectLinkingLayerCreator<br>>> +  Expected<std::unique_ptr<ObjectLayer>> operator()(ExecutionSession &,<br>>> +                                                    const Triple &);<br>>> +<br>>> +  Error addDebugSupport(ObjectLayer &ObjLayer);<br>>> +<br>>> +  Expected<std::unique_ptr<DefinitionGenerator>><br>>> +  loadDylib(StringRef RemotePath);<br>>> +<br>>> +  Expected<int> runAsMain(JITEvaluatedSymbol MainSym,<br>>> +                          ArrayRef<std::string> Args);<br>>> +  Error disconnect();<br>>> +<br>>> +  virtual ~JITLinkExecutor();<br>>> +<br>>> +protected:<br>>> +  std::unique_ptr<RemoteTargetProcessControl> TPC;<br>>> +<br>>> +  JITLinkExecutor();<br>>> +};<br>>> +<br>>> +/// JITLinkExecutor that runs in a child process on the local machine.<br>>> +class ChildProcessJITLinkExecutor : public JITLinkExecutor {<br>>> +public:<br>>> +  Error launch(ExecutionSession &ES);<br>>> +<br>>> +  pid_t getPID() const { return ProcessID; }<br>>> +  StringRef getPath() const { return ExecutablePath; }<br>>> +<br>>> +private:<br>>> +  std::string ExecutablePath;<br>>> +  pid_t ProcessID;<br>>> +<br>>> +  ChildProcessJITLinkExecutor(std::string ExecutablePath)<br>>> +      : ExecutablePath(std::move(ExecutablePath)) {}<br>>> +<br>>> +  static std::string defaultPath(const char *HostArgv0, StringRef ExecutorName);<br>>> +  friend class JITLinkExecutor;<br>>> +};<br>>> +<br>>> +/// JITLinkExecutor connected through a TCP socket.<br>>> +class TCPSocketJITLinkExecutor : public JITLinkExecutor {<br>>> +private:<br>>> +  TCPSocketJITLinkExecutor(std::unique_ptr<RemoteTargetProcessControl> TPC);<br>>> +<br>>> +  friend class JITLinkExecutor;<br>>> +};<br>>> +<br>>> +} // namespace orc<br>>> +} // namespace llvm<br>>> +<br>>> +#endif<br>>><br>>> diff  --git a/llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1.c b/llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1.c<br>>> new file mode 100644<br>>> index 000000000000..3a5c2bcefee1<br>>> --- /dev/null<br>>> +++ b/llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1.c<br>>> @@ -0,0 +1,2 @@<br>>> +int sub1(int x) { return x - 1; }<br>>> +int main(int argc, char **argv) { return sub1(argc); }<br>>><br>>> diff  --git a/llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1_elf.ll b/llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1_elf.ll<br>>> new file mode 100644<br>>> index 000000000000..659dbe109ec6<br>>> --- /dev/null<br>>> +++ b/llvm/test/Examples/OrcV2Examples/Inputs/argc_sub1_elf.ll<br>>> @@ -0,0 +1,52 @@<br>>> +; ModuleID = 'argc_sub1.c'<br>>> +target triple = "x86_64-unknown-unknown-elf"<br>>> +<br>>> +define i32 @sub1(i32) !dbg !8 {<br>>> +  call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()), !dbg !14<br>>> +  %2 = add nsw i32 %0, -1, !dbg !15<br>>> +  ret i32 %2, !dbg !16<br>>> +}<br>>> +<br>>> +define i32 @main(i32, i8** nocapture readnone) !dbg !17 {<br>>> +  call void @llvm.dbg.value(metadata i32 %0, metadata !24, metadata !DIExpression()), !dbg !26<br>>> +  call void @llvm.dbg.value(metadata i8** %1, metadata !25, metadata !DIExpression()), !dbg !27<br>>> +  %3 = tail call i32 @sub1(i32 %0), !dbg !28<br>>> +  ret i32 %3, !dbg !29<br>>> +}<br>>> +<br>>> +declare void @llvm.dbg.value(metadata, metadata, metadata)<br>>> +<br>>> +!<a href="http://llvm.dbg.cu">llvm.dbg.cu</a> = !{!0}<br>>> +!llvm.module.flags = !{!3, !4, !5, !6}<br>>> +!llvm.ident = !{!7}<br>>> +<br>>> +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)<br>>> +!1 = !DIFile(filename: "argc_sub1.c", directory: "Inputs/")<br>>> +!2 = !{}<br>>> +!3 = !{i32 2, !"Dwarf Version", i32 4}<br>>> +!4 = !{i32 2, !"Debug Info Version", i32 3}<br>>> +!5 = !{i32 1, !"wchar_size", i32 4}<br>>> +!6 = !{i32 7, !"PIC Level", i32 2}<br>>> +!7 = !{!"clang version 7.0.1-8+deb10u2 (tags/RELEASE_701/final)"}<br>>> +!8 = distinct !DISubprogram(name: "sub1", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12)<br>>> +!9 = !DISubroutineType(types: !10)<br>>> +!10 = !{!11, !11}<br>>> +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)<br>>> +!12 = !{!13}<br>>> +!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11)<br>>> +!14 = !DILocation(line: 1, column: 14, scope: !8)<br>>> +!15 = !DILocation(line: 1, column: 28, scope: !8)<br>>> +!16 = !DILocation(line: 1, column: 19, scope: !8)<br>>> +!17 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 2, type: !18, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !23)<br>>> +!18 = !DISubroutineType(types: !19)<br>>> +!19 = !{!11, !11, !20}<br>>> +!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 64)<br>>> +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64)<br>>> +!22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)<br>>> +!23 = !{!24, !25}<br>>> +!24 = !DILocalVariable(name: "argc", arg: 1, scope: !17, file: !1, line: 2, type: !11)<br>>> +!25 = !DILocalVariable(name: "argv", arg: 2, scope: !17, file: !1, line: 2, type: !20)<br>>> +!26 = !DILocation(line: 2, column: 14, scope: !17)<br>>> +!27 = !DILocation(line: 2, column: 27, scope: !17)<br>>> +!28 = !DILocation(line: 2, column: 42, scope: !17)<br>>> +!29 = !DILocation(line: 2, column: 35, scope: !17)<br>>><br>>> diff  --git a/llvm/test/Examples/OrcV2Examples/lljit-with-remote-debugging.test b/llvm/test/Examples/OrcV2Examples/lljit-with-remote-debugging.test<br>>> new file mode 100644<br>>> index 000000000000..a9c3946b55e2<br>>> --- /dev/null<br>>> +++ b/llvm/test/Examples/OrcV2Examples/lljit-with-remote-debugging.test<br>>> @@ -0,0 +1,10 @@<br>>> +# This test makes sure that the example builds and executes as expected.<br>>> +# Instructions for debugging can be found in LLJITWithRemoteDebugging.cpp<br>>> +<br>>> +# RUN: LLJITWithRemoteDebugging %p/Inputs/argc_sub1_elf.ll<br>>> +# CHECK: Running: {{.*}}/Inputs/argc_sub1_elf.ll<br>>> +# CHECK: Exit code: 0<br>>> +<br>>> +# RUN: LLJITWithRemoteDebugging %p/Inputs/argc_sub1_elf.ll --args 2nd 3rd 4th<br>>> +# CHECK: Running: {{.*}}/Inputs/argc_sub1_elf.ll 2nd 3rd 4th<br>>> +# CHECK: Exit code: 3<br>>><br>>><br>>><br>>> _______________________________________________<br>>> llvm-commits mailing list<br>>> <a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>>> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>><br>> --<br>> <a href="https://flowcrypt.com/pub/stefan.graenitz@gmail.com">https://flowcrypt.com/pub/stefan.graenitz@gmail.com</a></div>