summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/DWARF.cpp48
-rw-r--r--src/passes/pass.cpp5
-rw-r--r--src/passes/passes.h2
-rw-r--r--src/wasm-debug.h48
-rw-r--r--src/wasm/CMakeLists.txt1
-rw-r--r--src/wasm/wasm-debug.cpp151
7 files changed, 256 insertions, 0 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index 8eb3c7e88..456854644 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -18,6 +18,7 @@ set(passes_SOURCES
Directize.cpp
DuplicateImportElimination.cpp
DuplicateFunctionElimination.cpp
+ DWARF.cpp
ExtractFunction.cpp
Flatten.cpp
FuncCastEmulation.cpp
diff --git a/src/passes/DWARF.cpp b/src/passes/DWARF.cpp
new file mode 100644
index 000000000..fe595adae
--- /dev/null
+++ b/src/passes/DWARF.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Dump DWARF sections. This results in something similar to llvm-dwarfdump,
+// as it uses the same code.
+//
+// Note that this dumps the DWARF data read from the binary when we loaded it.
+// It does not contain changes made since then, which will only be updated
+// when we write the binary. To see those changes, you must round-trip.
+//
+
+#include "pass.h"
+#include "wasm-debug.h"
+#include "wasm.h"
+
+namespace wasm {
+
+struct DWARFDump : public Pass {
+ void run(PassRunner* runner, Module* module) override {
+ Debug::dumpDWARF(*module);
+ }
+};
+
+struct DWARFUpdate : public Pass {
+ void run(PassRunner* runner, Module* module) override {
+ Debug::writeDWARFSections(*module);
+ }
+};
+
+Pass* createDWARFDumpPass() { return new DWARFDump(); }
+
+Pass* createDWARFUpdatePass() { return new DWARFUpdate(); }
+
+} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 113017df5..cbc8e3be9 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -107,6 +107,11 @@ void PassRegistry::registerPasses() {
"directize", "turns indirect calls into direct ones", createDirectizePass);
registerPass(
"dfo", "optimizes using the DataFlow SSA IR", createDataFlowOptsPass);
+ registerPass("dwarfdump",
+ "dump DWARF debug info sections from the read binary",
+ createDWARFDumpPass);
+ registerPass(
+ "dwarfupdate", "update DWARF debug info sections", createDWARFUpdatePass);
registerPass("duplicate-import-elimination",
"removes duplicate imports",
createDuplicateImportEliminationPass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index 33a0b26da..2f30441db 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -35,6 +35,8 @@ Pass* createDAEOptimizingPass();
Pass* createDataFlowOptsPass();
Pass* createDeadCodeEliminationPass();
Pass* createDirectizePass();
+Pass* createDWARFDumpPass();
+Pass* createDWARFUpdatePass();
Pass* createDuplicateImportEliminationPass();
Pass* createDuplicateFunctionEliminationPass();
Pass* createEmitTargetFeaturesPass();
diff --git a/src/wasm-debug.h b/src/wasm-debug.h
new file mode 100644
index 000000000..d2e4840f1
--- /dev/null
+++ b/src/wasm-debug.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Comprehensive debug info support (beyond source maps).
+//
+
+#ifndef wasm_wasm_debug_h
+#define wasm_wasm_debug_h
+
+#include <string>
+
+#include "wasm.h"
+
+namespace wasm {
+
+namespace Debug {
+
+bool isDWARFSection(Name name);
+
+bool hasDWARFSections(const Module& wasm);
+
+// Dump the DWARF sections to stdout.
+void dumpDWARF(const Module& wasm);
+
+// Update the DWARF sections.
+void writeDWARFSections(Module& wasm);
+
+} // namespace Debug
+
+} // namespace wasm
+
+#undef DEBUG_TYPE
+
+#endif // wasm_wasm_debug_h
diff --git a/src/wasm/CMakeLists.txt b/src/wasm/CMakeLists.txt
index dab974ea4..38bbc97fb 100644
--- a/src/wasm/CMakeLists.txt
+++ b/src/wasm/CMakeLists.txt
@@ -3,6 +3,7 @@ set(wasm_SOURCES
wasm.cpp
wasm-binary.cpp
wasm-emscripten.cpp
+ wasm-debug.cpp
wasm-interpreter.cpp
wasm-io.cpp
wasm-s-parser.cpp
diff --git a/src/wasm/wasm-debug.cpp b/src/wasm/wasm-debug.cpp
new file mode 100644
index 000000000..595c7f50b
--- /dev/null
+++ b/src/wasm/wasm-debug.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2019 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wasm-debug.h"
+#include "wasm.h"
+
+#ifdef BUILD_LLVM_DWARF
+#include "llvm/ObjectYAML/DWARFEmitter.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
+#include "llvm/include/llvm/DebugInfo/DWARFContext.h"
+
+std::error_code dwarf2yaml(llvm::DWARFContext& DCtx, llvm::DWARFYAML::Data& Y);
+#endif
+
+namespace wasm {
+
+namespace Debug {
+
+bool isDWARFSection(Name name) { return name.startsWith(".debug_"); }
+
+bool hasDWARFSections(const Module& wasm) {
+ for (auto& section : wasm.userSections) {
+ if (isDWARFSection(section.name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef BUILD_LLVM_DWARF
+
+struct BinaryenDWARFInfo {
+ llvm::StringMap<std::unique_ptr<llvm::MemoryBuffer>> sections;
+ std::unique_ptr<llvm::DWARFContext> context;
+
+ BinaryenDWARFInfo(const Module& wasm) {
+ // Get debug sections from the wasm.
+ for (auto& section : wasm.userSections) {
+ if (Name(section.name).startsWith(".debug_")) {
+ // TODO: efficiency
+ sections[section.name.substr(1)] = llvm::MemoryBuffer::getMemBufferCopy(
+ llvm::StringRef(section.data.data(), section.data.size()));
+ }
+ }
+ // Parse debug sections.
+ uint8_t addrSize = 4;
+ context = llvm::DWARFContext::create(sections, addrSize);
+ }
+};
+
+void dumpDWARF(const Module& wasm) {
+ BinaryenDWARFInfo info(wasm);
+ std::cout << "DWARF debug info\n";
+ std::cout << "================\n\n";
+ for (auto& section : wasm.userSections) {
+ if (Name(section.name).startsWith(".debug_")) {
+ std::cout << "Contains section " << section.name << " ("
+ << section.data.size() << " bytes)\n";
+ }
+ }
+ llvm::DIDumpOptions options;
+ options.Verbose = true;
+ info.context->dump(llvm::outs(), options);
+}
+
+//
+// Big picture: We use a DWARFContext to read data, then DWARFYAML support
+// code to write it. That is not the main LLVM Dwarf code used for writing
+// object files, but it avoids us create a "fake" MC layer, and provides a
+// simple way to write out the debug info. Likely the level of info represented
+// in the DWARFYAML::Data object is sufficient for Binaryen's needs, but if not,
+// we may need a different approach.
+//
+// In more detail:
+//
+// 1. Binary sections => DWARFContext:
+//
+// llvm::DWARFContext::create(sections..)
+//
+// 2. DWARFContext => DWARFYAML::Data
+//
+// std::error_code dwarf2yaml(DWARFContext &DCtx, DWARFYAML::Data &Y) {
+//
+// 3. DWARFYAML::Data => binary sections
+//
+// StringMap<std::unique_ptr<MemoryBuffer>>
+// EmitDebugSections(llvm::DWARFYAML::Data &DI, bool ApplyFixups);
+//
+// For modifying data, like line numberes, we can in theory do that either on
+// the DWARFContext or DWARFYAML::Data; unclear which is best, but modifying
+// the DWARFContext may save us doing fixups in EmitDebugSections.
+//
+
+void writeDWARFSections(Module& wasm) {
+ BinaryenDWARFInfo info(wasm);
+
+ // Convert to Data representation, which YAML can use to write.
+ llvm::DWARFYAML::Data Data;
+ if (dwarf2yaml(*info.context, Data)) {
+ Fatal() << "Failed to parse DWARF to YAML";
+ }
+
+ // TODO: Actually update, and remove sections we don't know how to update yet?
+
+ // Convert to binary sections.
+ auto newSections = EmitDebugSections(
+ Data,
+ false /* ApplyFixups, should be true if we modify Data, presumably? */);
+
+ // Update the custom sections in the wasm.
+ // TODO: efficiency
+ for (auto& section : wasm.userSections) {
+ if (Name(section.name).startsWith(".debug_")) {
+ auto llvmName = section.name.substr(1);
+ if (newSections.count(llvmName)) {
+ auto llvmData = newSections[llvmName]->getBuffer();
+ section.data.resize(llvmData.size());
+ std::copy(llvmData.begin(), llvmData.end(), section.data.data());
+ }
+ }
+ }
+}
+
+#else // BUILD_LLVM_DWARF
+
+void dumpDWARF(const Module& wasm) {
+ std::cerr << "warning: no DWARF dumping support present\n";
+}
+
+void writeDWARFSections(Module& wasm) {
+ std::cerr << "warning: no DWARF updating support present\n";
+}
+
+#endif // BUILD_LLVM_DWARF
+
+} // namespace Debug
+
+} // namespace wasm