/* * 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> sections; std::unique_ptr 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> // 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