[WebAssembly] Add --reproduce.

--reproduce is a convenient option for debugging. If you invoke lld
with `--reproduce=repro.tar`, it creates `repro.tar` with all input
files and the command line options given to the linker, so that it is
very easy to run lld with the exact same inputs.

ELF and Windows lld have this option.

This patch add that option to lld/wasm.

Differential Revision: https://reviews.llvm.org/D62170

llvm-svn: 361244
This commit is contained in:
Rui Ueyama 2019-05-21 11:52:14 +00:00
parent bc03bee66b
commit 35150bb534
5 changed files with 87 additions and 0 deletions

View File

@ -0,0 +1,27 @@
; REQUIRES: shell
; RUN: rm -rf %t.dir
; RUN: mkdir -p %t.dir
; RUN: llc -filetype=obj %s -o %t.dir/foo.o
; RUN: wasm-ld --reproduce=%t.dir/repro.tar -o out.wasm %t.dir/foo.o
; RUN: cd %t.dir
; RUN: tar tf repro.tar | FileCheck --check-prefix=TAR
; TAR: repro/response.txt
; TAR: repro/version.txt
; TAR: repro/{{.*}}/foo.o
; RUN: tar xf repro.tar
; RUN: FileCheck --check-prefix=RSP %s < repro/response.txt
; RSP: -o out.wasm
; RSP: {{.*}}/foo.o
; RUN: FileCheck %s --check-prefix=VERSION < repro/version.txt
; VERSION: LLD
target triple = "wasm32-unknown-unknown"
define void @_start() {
ret void
}

View File

@ -16,6 +16,7 @@
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "lld/Common/Strings.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
@ -26,6 +27,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
#define DEBUG_TYPE "lld"
@ -504,6 +506,34 @@ static void createSyntheticSymbols() {
"__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
}
// Reconstructs command line arguments so that so that you can re-run
// the same command with the same inputs. This is for --reproduce.
static std::string createResponseFile(const opt::InputArgList &Args) {
SmallString<0> Data;
raw_svector_ostream OS(Data);
// Copy the command line to the output while rewriting paths.
for (auto *Arg : Args) {
switch (Arg->getOption().getUnaliasedOption().getID()) {
case OPT_reproduce:
break;
case OPT_INPUT:
OS << quote(relativeToRoot(Arg->getValue())) << "\n";
break;
case OPT_o:
// If -o path contains directories, "lld @response.txt" will likely
// fail because the archive we are creating doesn't contain empty
// directories for the output path (-o doesn't create directories).
// Strip directories to prevent the issue.
OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
break;
default:
OS << toString(*Arg) << "\n";
}
}
return Data.str();
}
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
WasmOptTable Parser;
opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
@ -522,6 +552,20 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
return;
}
// Handle --reproduce
if (auto *Arg = Args.getLastArg(OPT_reproduce)) {
StringRef Path = Arg->getValue();
Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
TarWriter::create(Path, path::stem(Path));
if (ErrOrWriter) {
Tar = std::move(*ErrOrWriter);
Tar->append("response.txt", createResponseFile(Args));
Tar->append("version.txt", getLLDVersion() + "\n");
} else {
error("--reproduce: " + toString(ErrOrWriter.takeError()));
}
}
// Parse and evaluate -mllvm options.
std::vector<const char *> V;
V.push_back("wasm-ld (LLVM option parsing)");

View File

@ -14,8 +14,10 @@
#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Reproduce.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/raw_ostream.h"
#define DEBUG_TYPE "lld"
@ -27,6 +29,8 @@ using namespace llvm;
using namespace llvm::object;
using namespace llvm::wasm;
std::unique_ptr<llvm::TarWriter> lld::wasm::Tar;
Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
log("Loading: " + Path);
@ -39,6 +43,8 @@ Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
MemoryBufferRef MBRef = MB->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
if (Tar)
Tar->append(relativeToRoot(Path), MBRef.getBuffer());
return MBRef;
}

View File

@ -19,6 +19,10 @@
#include "llvm/Support/MemoryBuffer.h"
#include <vector>
namespace llvm {
class TarWriter;
}
namespace lld {
namespace wasm {
@ -29,6 +33,10 @@ class InputGlobal;
class InputEvent;
class InputSection;
// If --reproduce option is given, all input files are written
// to this tar archive.
extern std::unique_ptr<llvm::TarWriter> Tar;
class InputFile {
public:
enum Kind {

View File

@ -85,6 +85,8 @@ defm print_gc_sections: B<"print-gc-sections",
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">;
def shared: F<"shared">, HelpText<"Build a shared object">;
def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;