| //===----------------------------------------------------------------------===// |
| // |
| // 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 LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_WASMADDRESS_H |
| #define LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_WASMADDRESS_H |
| |
| #include "lldb/lldb-defines.h" |
| #include "lldb/lldb-types.h" |
| #include <cstdint> |
| |
| namespace lldb_private { |
| namespace wasm { |
| |
| /// Each WebAssembly module has separate address spaces for Code and Memory. A |
| /// WebAssembly module also has a Data section which, when the module is loaded, |
| /// gets mapped into a region in the module Memory. |
| /// |
| /// Globals are not addressable: they live in an index space of their own. The |
| /// synthetic Global space stands in for one, holding the index where an address |
| /// would hold an offset, so that a global can be named and read. |
| /// |
| /// The tag is two bits wide and these are the only spaces there are, so the |
| /// remaining value means an address that belongs to nothing. |
| enum WasmAddressType : uint8_t { |
| Memory = 0x00, |
| Object = 0x01, |
| Global = 0x02, |
| Invalid = 0x03, |
| }; |
| |
| /// Widths of the fields a 64-bit address is made of, from the low bits up. The |
| /// bitfields below are declared with the same constants, so a field and the |
| /// mask that extracts it cannot come to disagree. |
| static constexpr uint32_t kWasmOffsetBits = 32; |
| static constexpr uint32_t kWasmModuleIDBits = 30; |
| static constexpr uint32_t kWasmAddressTypeBits = 2; |
| |
| static_assert(kWasmOffsetBits + kWasmModuleIDBits + kWasmAddressTypeBits == 64, |
| "a Wasm address has to account for all 64 bits"); |
| |
| static constexpr uint32_t kWasmModuleIDShift = kWasmOffsetBits; |
| static constexpr uint32_t kWasmAddressTypeShift = |
| kWasmModuleIDShift + kWasmModuleIDBits; |
| |
| static constexpr uint64_t MakeFieldMask(uint32_t bits, uint32_t shift) { |
| return ((uint64_t(1) << bits) - 1) << shift; |
| } |
| |
| static constexpr uint64_t kWasmOffsetMask = MakeFieldMask(kWasmOffsetBits, 0); |
| static constexpr uint64_t kWasmModuleIDMask = |
| MakeFieldMask(kWasmModuleIDBits, kWasmModuleIDShift); |
| static constexpr uint64_t kWasmAddressTypeMask = |
| MakeFieldMask(kWasmAddressTypeBits, kWasmAddressTypeShift); |
| |
| /// A value that names no module. Every value the id field can hold names a |
| /// module, zero included, so the sentinel has to come from outside that range. |
| static constexpr uint32_t kWasmInvalidModuleID = UINT32_MAX; |
| |
| static_assert(kWasmInvalidModuleID > (kWasmModuleIDMask >> kWasmModuleIDShift), |
| "the sentinel has to fall outside the range of a module id"); |
| |
| /// For the purpose of debugging, we can represent all these separated 32-bit |
| /// address spaces with a single virtual 64-bit address space. The |
| /// wasm_addr_t provides this encoding using bitfields. |
| struct wasm_addr_t { |
| uint64_t offset : kWasmOffsetBits; |
| uint64_t module_id : kWasmModuleIDBits; |
| uint64_t type : kWasmAddressTypeBits; |
| |
| wasm_addr_t(lldb::addr_t addr) |
| : offset(addr & kWasmOffsetMask), |
| module_id((addr & kWasmModuleIDMask) >> kWasmModuleIDShift), |
| type(addr >> kWasmAddressTypeShift) {} |
| |
| wasm_addr_t(WasmAddressType type, uint32_t module_id, uint32_t offset) |
| : offset(offset), module_id(module_id), type(type) {} |
| |
| WasmAddressType GetType() const { return static_cast<WasmAddressType>(type); } |
| uint32_t GetModuleID() const { return module_id; } |
| uint32_t GetOffset() const { return offset; } |
| |
| operator lldb::addr_t() { return *(uint64_t *)this; } |
| }; |
| |
| static_assert(sizeof(wasm_addr_t) == 8, ""); |
| |
| /// The module an address belongs to, or kWasmInvalidModuleID for an invalid |
| /// address. |
| inline uint32_t GetWasmModuleID(lldb::addr_t addr) { |
| if (addr == LLDB_INVALID_ADDRESS) |
| return kWasmInvalidModuleID; |
| return wasm_addr_t(addr).GetModuleID(); |
| } |
| |
| } // namespace wasm |
| } // namespace lldb_private |
| |
| #endif |