Skip to content

Commit

Permalink
[WebAssembly] Add --reproduce.
Browse files Browse the repository at this point in the history
--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
  • Loading branch information
rui314 authored and MrSidims committed May 24, 2019
1 parent fd62634 commit a6265c3
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lld/test/wasm/reproduce.ll
@@ -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
}
44 changes: 44 additions & 0 deletions lld/wasm/Driver.cpp
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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));
Expand All @@ -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)");
Expand Down
6 changes: 6 additions & 0 deletions lld/wasm/InputFiles.cpp
Expand Up @@ -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"
Expand All @@ -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);

Expand All @@ -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;
}

Expand Down
8 changes: 8 additions & 0 deletions lld/wasm/InputFiles.h
Expand Up @@ -19,6 +19,10 @@
#include "llvm/Support/MemoryBuffer.h"
#include <vector>

namespace llvm {
class TarWriter;
}

namespace lld {
namespace wasm {

Expand All @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions lld/wasm/Options.td
Expand Up @@ -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">;
Expand Down

0 comments on commit a6265c3

Please sign in to comment.