Skip to content

Commit

Permalink
[LLDB] Add DynamicLoaderWasmDYLD plugin for WebAssembly debugging
Browse files Browse the repository at this point in the history
Add a dynamic loader plug-in class for WebAssembly modules.

Differential Revision: https://reviews.llvm.org/D72751
  • Loading branch information
paolosevMSFT authored and labath committed Feb 17, 2020
1 parent aedc196 commit c112190
Show file tree
Hide file tree
Showing 16 changed files with 464 additions and 39 deletions.
3 changes: 3 additions & 0 deletions lldb/source/API/SystemInitializerFull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ LLDB_PLUGIN_DECLARE(ProcessGDBRemote)
LLDB_PLUGIN_DECLARE(DynamicLoaderMacOSXDYLD)
LLDB_PLUGIN_DECLARE(DynamicLoaderPOSIXDYLD)
LLDB_PLUGIN_DECLARE(DynamicLoaderStatic)
LLDB_PLUGIN_DECLARE(DynamicLoaderWasmDYLD)
LLDB_PLUGIN_DECLARE(DynamicLoaderWindowsDYLD)

using namespace lldb_private;
Expand Down Expand Up @@ -240,6 +241,7 @@ llvm::Error SystemInitializerFull::Initialize() {
LLDB_PLUGIN_INITIALIZE(ProcessGDBRemote);
LLDB_PLUGIN_INITIALIZE(DynamicLoaderMacOSXDYLD);
LLDB_PLUGIN_INITIALIZE(DynamicLoaderPOSIXDYLD);
LLDB_PLUGIN_INITIALIZE(DynamicLoaderWasmDYLD); // Before DynamicLoaderStatic.
LLDB_PLUGIN_INITIALIZE(DynamicLoaderStatic);
LLDB_PLUGIN_INITIALIZE(DynamicLoaderWindowsDYLD);

Expand Down Expand Up @@ -327,6 +329,7 @@ void SystemInitializerFull::Terminate() {

LLDB_PLUGIN_TERMINATE(DynamicLoaderMacOSXDYLD);
LLDB_PLUGIN_TERMINATE(DynamicLoaderPOSIXDYLD);
LLDB_PLUGIN_TERMINATE(DynamicLoaderWasmDYLD);
LLDB_PLUGIN_TERMINATE(DynamicLoaderStatic);
LLDB_PLUGIN_TERMINATE(DynamicLoaderWindowsDYLD);

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Plugins/DynamicLoader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ add_subdirectory(POSIX-DYLD)
add_subdirectory(Static)
add_subdirectory(Hexagon-DYLD)
add_subdirectory(Windows-DYLD)
add_subdirectory(wasm-DYLD)
9 changes: 9 additions & 0 deletions lldb/source/Plugins/DynamicLoader/wasm-DYLD/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_lldb_library(lldbPluginDynamicLoaderWasmDYLD PLUGIN
DynamicLoaderWasmDYLD.cpp

LINK_LIBS
lldbCore
lldbTarget
LINK_COMPONENTS
Support
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//===-- DynamicLoaderWasmDYLD.cpp -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "DynamicLoaderWasmDYLD.h"

#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::wasm;

LLDB_PLUGIN_DEFINE(DynamicLoaderWasmDYLD)

DynamicLoaderWasmDYLD::DynamicLoaderWasmDYLD(Process *process)
: DynamicLoader(process) {}

void DynamicLoaderWasmDYLD::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance);
}

ConstString DynamicLoaderWasmDYLD::GetPluginNameStatic() {
static ConstString g_plugin_name("wasm-dyld");
return g_plugin_name;
}

const char *DynamicLoaderWasmDYLD::GetPluginDescriptionStatic() {
return "Dynamic loader plug-in that watches for shared library "
"loads/unloads in WebAssembly engines.";
}

DynamicLoader *DynamicLoaderWasmDYLD::CreateInstance(Process *process,
bool force) {
bool should_create = force;
if (!should_create) {
should_create =
(process->GetTarget().GetArchitecture().GetTriple().getArch() ==
llvm::Triple::wasm32);
}

if (should_create)
return new DynamicLoaderWasmDYLD(process);

return nullptr;
}

void DynamicLoaderWasmDYLD::DidAttach() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
LLDB_LOGF(log, "DynamicLoaderWasmDYLD::%s()", __FUNCTION__);

// Ask the process for the list of loaded WebAssembly modules.
auto error = m_process->LoadModules();
LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}");
}

ThreadPlanSP DynamicLoaderWasmDYLD::GetStepThroughTrampolinePlan(Thread &thread,
bool stop) {
return ThreadPlanSP();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//===-- DynamicLoaderWasmDYLD.h ---------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_Plugins_DynamicLoaderWasmDYLD_h_
#define liblldb_Plugins_DynamicLoaderWasmDYLD_h_

#include "lldb/Target/DynamicLoader.h"

namespace lldb_private {
namespace wasm {

class DynamicLoaderWasmDYLD : public DynamicLoader {
public:
DynamicLoaderWasmDYLD(Process *process);

static void Initialize();
static void Terminate() {}

static ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();

static DynamicLoader *CreateInstance(Process *process, bool force);

/// DynamicLoader
/// \{
void DidAttach() override;
void DidLaunch() override {}
Status CanLoadImage() override { return Status(); }
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
bool stop) override;
/// \}

/// PluginInterface protocol.
/// \{
ConstString GetPluginName() override { return GetPluginNameStatic(); }
uint32_t GetPluginVersion() override { return 1; }
/// \}
};

} // namespace wasm
} // namespace lldb_private

#endif // liblldb_Plugins_DynamicLoaderWasmDYLD_h_
41 changes: 23 additions & 18 deletions lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp,
offset_t data_offset, const FileSpec *file,
offset_t offset, offset_t length)
: ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
m_arch("wasm32-unknown-unknown-wasm"), m_code_section_offset(0) {
m_arch("wasm32-unknown-unknown-wasm") {
m_data.SetAddressByteSize(4);
}

Expand All @@ -244,7 +244,7 @@ ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
const lldb::ProcessSP &process_sp,
lldb::addr_t header_addr)
: ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
m_arch("wasm32-unknown-unknown-wasm"), m_code_section_offset(0) {}
m_arch("wasm32-unknown-unknown-wasm") {}

bool ObjectFileWasm::ParseHeader() {
// We already parsed the header during initialization.
Expand All @@ -266,15 +266,19 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
for (const section_info &sect_info : m_sect_infos) {
SectionType section_type = eSectionTypeOther;
ConstString section_name;
offset_t file_offset = 0;
addr_t vm_addr = 0;
size_t vm_size = 0;
offset_t file_offset = sect_info.offset & 0xffffffff;
addr_t vm_addr = file_offset;
size_t vm_size = sect_info.size;

if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
section_type = eSectionTypeCode;
section_name = ConstString("code");
m_code_section_offset = sect_info.offset & 0xffffffff;
vm_size = sect_info.size;

// A code address in DWARF for WebAssembly is the offset of an
// instruction relative within the Code section of the WebAssembly file.
// For this reason Section::GetFileAddress() must return zero for the
// Code section.
vm_addr = 0;
} else {
section_type =
llvm::StringSwitch<SectionType>(sect_info.name.GetStringRef())
Expand Down Expand Up @@ -302,10 +306,9 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
if (section_type == eSectionTypeOther)
continue;
section_name = sect_info.name;
file_offset = sect_info.offset & 0xffffffff;
if (IsInMemory()) {
vm_addr = sect_info.offset & 0xffffffff;
vm_size = sect_info.size;
if (!IsInMemory()) {
vm_size = 0;
vm_addr = 0;
}
}

Expand Down Expand Up @@ -345,6 +348,10 @@ bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
/// 0x0000000400000000 for module_id == 4.
/// These 64-bit addresses will be used to request code ranges for a specific
/// module from the WebAssembly engine.

assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
m_memory_addr == load_address);

ModuleSP module_sp = GetModule();
if (!module_sp)
return false;
Expand All @@ -357,24 +364,22 @@ bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
return false;

const size_t num_sections = section_list->GetSize();
size_t sect_idx = 0;

for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
if (target.GetSectionLoadList().SetSectionLoadAddress(
section_sp, load_address | section_sp->GetFileAddress())) {
if (target.SetSectionLoadAddress(
section_sp, load_address | section_sp->GetFileOffset())) {
++num_loaded_sections;
}
}

return num_loaded_sections > 0;
}

DataExtractor ObjectFileWasm::ReadImageData(uint64_t offset, size_t size) {
DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
DataExtractor data;
if (m_file) {
if (offset < GetByteSize()) {
size = std::min(size, (size_t) (GetByteSize() - offset));
size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
auto buffer_sp = MapFileData(m_file, size, offset);
return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
}
Expand Down
12 changes: 5 additions & 7 deletions lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class ObjectFileWasm : public ObjectFile {
return m_arch.GetByteOrder();
}

bool IsExecutable() const override { return true; }
bool IsExecutable() const override { return false; }

uint32_t GetAddressByteSize() const override {
return m_arch.GetAddressByteSize();
Expand All @@ -81,7 +81,7 @@ class ObjectFileWasm : public ObjectFile {

Symtab *GetSymtab() override;

bool IsStripped() override { return true; }
bool IsStripped() override { return !!GetExternalDebugInfoFileSpec(); }

void CreateSections(SectionList &unified_section_list) override;

Expand All @@ -93,16 +93,15 @@ class ObjectFileWasm : public ObjectFile {

uint32_t GetDependentModules(FileSpecList &files) override { return 0; }

Type CalculateType() override { return eTypeExecutable; }
Type CalculateType() override { return eTypeSharedLibrary; }

Strata CalculateStrata() override { return eStrataUser; }

bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value,
bool value_is_offset) override;

lldb_private::Address GetBaseAddress() override {
return IsInMemory() ? Address(m_memory_addr + m_code_section_offset)
: Address(m_code_section_offset);
return IsInMemory() ? Address(m_memory_addr) : Address(0);
}
/// \}

Expand All @@ -127,7 +126,7 @@ class ObjectFileWasm : public ObjectFile {
/// \}

/// Read a range of bytes from the Wasm module.
DataExtractor ReadImageData(uint64_t offset, size_t size);
DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size);

typedef struct section_info {
lldb::offset_t offset;
Expand All @@ -145,7 +144,6 @@ class ObjectFileWasm : public ObjectFile {
std::vector<section_info_t> m_sect_infos;
ArchSpec m_arch;
UUID m_uuid;
uint32_t m_code_section_offset;
};

} // namespace wasm
Expand Down
Loading

0 comments on commit c112190

Please sign in to comment.