summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-debug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-debug.cpp')
-rw-r--r--src/wasm/wasm-debug.cpp151
1 files changed, 151 insertions, 0 deletions
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