diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/DWARF.cpp | 48 | ||||
-rw-r--r-- | src/passes/pass.cpp | 5 | ||||
-rw-r--r-- | src/passes/passes.h | 2 | ||||
-rw-r--r-- | src/wasm-debug.h | 48 | ||||
-rw-r--r-- | src/wasm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/wasm/wasm-debug.cpp | 151 |
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 |