Index: lldb/test/Shell/Reproducer/lit.local.cfg =================================================================== --- lldb/test/Shell/Reproducer/lit.local.cfg +++ lldb/test/Shell/Reproducer/lit.local.cfg @@ -4,3 +4,7 @@ if 'LLDB_CAPTURE_REPRODUCER' in config.environment: del config.environment['LLDB_CAPTURE_REPRODUCER'] + +if 'LLDB_REPRO_CAPTURE' in config.environment or \ + 'LLDB_REPRO_REPLAY' in config.environment: + config.unsupported = True Index: lldb/test/Shell/lit.cfg.py =================================================================== --- lldb/test/Shell/lit.cfg.py +++ lldb/test/Shell/lit.cfg.py @@ -38,10 +38,15 @@ # test_exec_root: The root path where tests should be run. config.test_exec_root = os.path.join(config.lldb_obj_root, 'test') -# Propagate LLDB_CAPTURE_REPRODUCER +# Propagate reproducer environment vars. if 'LLDB_CAPTURE_REPRODUCER' in os.environ: config.environment['LLDB_CAPTURE_REPRODUCER'] = os.environ[ 'LLDB_CAPTURE_REPRODUCER'] +if 'LLDB_REPRO_CAPTURE' in os.environ: + config.environment['LLDB_REPRO_CAPTURE'] = os.environ['LLDB_REPRO_CAPTURE'] + +if 'LLDB_REPRO_REPLAY' in os.environ: + config.environment['LLDB_REPRO_REPLAY'] = os.environ['LLDB_REPRO_REPLAY'] llvm_config.use_default_substitutions() toolchain.use_lldb_substitutions(config) Index: lldb/tools/CMakeLists.txt =================================================================== --- lldb/tools/CMakeLists.txt +++ lldb/tools/CMakeLists.txt @@ -7,7 +7,11 @@ # example is `check-lldb`. So, we pass EXCLUDE_FROM_ALL here. add_subdirectory(lldb-test EXCLUDE_FROM_ALL) -add_lldb_tool_subdirectory(lldb-instr) +if(LLDB_INCLUDE_TESTS) + add_lldb_tool_subdirectory(lldb-instr) +endif() + +add_lldb_tool_subdirectory(lldb-repro) add_lldb_tool_subdirectory(lldb-vscode) if (CMAKE_SYSTEM_NAME MATCHES "Darwin") Index: lldb/tools/lldb-repro/CMakeLists.txt =================================================================== --- /dev/null +++ lldb/tools/lldb-repro/CMakeLists.txt @@ -0,0 +1,10 @@ +set(lldb_repro_input ${CMAKE_CURRENT_SOURCE_DIR}/lldb-repro.h.cmake) +set(lldb_repro_output ${CMAKE_CURRENT_BINARY_DIR}/lldb-repro.h) +configure_file(${lldb_repro_input} ${lldb_repro_output}) + +add_lldb_tool(lldb-repro + lldb-repro.cpp + + LINK_COMPONENTS + Support + ) Index: lldb/tools/lldb-repro/lldb-repro.h.cmake =================================================================== --- /dev/null +++ lldb/tools/lldb-repro/lldb-repro.h.cmake @@ -0,0 +1,14 @@ +//===-- lldb-repro.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_REPRO_H +#define LLDB_TOOLS_LLDB_REPRO_H + +#cmakedefine LLDB_TEST_EXECUTABLE "${LLDB_TEST_EXECUTABLE}" + +#endif Index: lldb/tools/lldb-repro/lldb-repro.cpp =================================================================== --- /dev/null +++ lldb/tools/lldb-repro/lldb-repro.cpp @@ -0,0 +1,76 @@ +//===-- lldb-repro.cpp ----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb-repro.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DJB.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm; + +unsigned ComputerHash(StringRef args, StringRef cwd) { + const unsigned hash = djbHash(cwd); + return djbHash(args, hash); +} + +int main(int argc, const char **argv) { + std::string arg_str; + for (int i = 1; i < argc; ++i) + arg_str.append(argv[i]); + + SmallString<256> cwd_str; + sys::fs::current_path(cwd_str); + + // Compute the hash. + const unsigned hash = ComputerHash(arg_str, cwd_str.str()); + + // Compute the reproducer directory. + const char *tmpdir = getenv("TMPDIR"); + if (!tmpdir) { + WithColor::error() << "unable to get the temp directory form TMPDIR\n"; + return 1; + } + + SmallString<256> repro_dir; + llvm::sys::path::system_temp_directory(true, repro_dir); + sys::path::append(repro_dir, std::to_string(hash)); + + // Construct the lldb argument list. + std::vector args; + args.push_back(LLDB_TEST_EXECUTABLE); + if (getenv("LLDB_REPRO_REPLAY")) { + args.push_back("--replay"); + args.push_back(repro_dir.c_str()); + } else if (getenv("LLDB_REPRO_CAPTURE")) { + // Remove any previous reproducer. + sys::fs::remove_directories(repro_dir); + + args.push_back("--capture"); + args.push_back("--capture-path"); + args.push_back(repro_dir.c_str()); + args.push_back("--reproducer-auto-generate"); + + // Append the original arguments. + for (int i = 1; i < argc; ++i) + args.push_back(argv[i]); + } else { + WithColor::error() + << "enable capture or replay by setting the environment variables " + "LLDB_REPRO_CAPTURE and LLDB_REPRO_REPLAY respectively\n"; + return 1; + } + + return llvm::sys::ExecuteAndWait(LLDB_TEST_EXECUTABLE, args); +}