Bring loader in sync with stg/sc

Change-Id: Iccce07b8fa03d37c4267a2a9bd343e6614dc43e7


[ROCm/ROCR-Runtime commit: 9887c26113]
Этот коммит содержится в:
Konstantin Zhuravlyov committed 2017-02-10 11:21:15 -05:00
1 родитель 16d8e2caa9
Коммит 2a071e1456
8 files changed
+244 -130

No files matched your search

+3
Просмотреть файл
@@ -183,6 +183,9 @@ namespace code {
static Symbol* FromHandle(hsa_code_symbol_t handle);
void setValue(uint64_t value) { elfsym->setValue(value); }
void setSize(uint32_t size) { elfsym->setSize(size); }
std::string GetModuleName() const;
std::string GetSymbolName() const;
};
class KernelSymbol : public Symbol {
+3
Просмотреть файл
@@ -408,6 +408,9 @@ public:
/// invalid address, returns null pointer.
virtual uint64_t FindHostAddress(uint64_t device_address) = 0;
/// @brief Print loader help.
virtual void PrintHelp(std::ostream& out) = 0;
protected:
/// @brief Default constructor.
Loader() {}
+29 -8
Просмотреть файл
@@ -41,6 +41,7 @@
////////////////////////////////////////////////////////////////////////////////
#include "amd_elf_image.hpp"
#include "amd_hsa_code_util.hpp"
#include <gelf.h>
#include <errno.h>
#include <cstring>
@@ -50,7 +51,6 @@
#include <cassert>
#include <cstdlib>
#include <algorithm>
#include "amd_hsa_code_util.hpp"
#ifdef _WIN32
#include <Windows.h>
#define alignof __alignof
@@ -60,17 +60,38 @@
#ifndef _WIN32
#define _open open
#define _close close
#define _tempnam tempnam
#include <fcntl.h>
#include <unistd.h>
#endif
#if defined(USE_MEMFILE)
#include "memfile.h"
#define OpenTemp(f) mem_open(NULL, 0, 0)
#define CloseTemp(f) mem_close(f)
#define _read(f, b, l) mem_read((f), (b), (l))
#define _write(f, b, l) mem_write((f), (b), (l))
#define _lseek(f, l, w) mem_lseek((f), (l), (w))
#define _ftruncate(f, l) mem_ftruncate((f), (size_t)(l))
#define sendfile(o, i, p, s) mem_sendfile((o), (i), (p), (s))
#else // USE_MEMFILE
#define OpenTemp(f) amd::hsa::OpenTempFile(f);
#define CloseTemp(f) amd::hsa::CloseTempFile(f);
#ifndef _WIN32
#define _read read
#define _write write
#define _lseek lseek
#define _ftruncate ftruncate
#define _tempnam tempnam
#include <sys/sendfile.h>
#include <fcntl.h>
#include <unistd.h>
#else
#define _ftruncate _chsize
#endif
#endif // !_WIN32
#endif // !USE_MEMFILE
#if !defined(BSD_LIBELF)
#define elf_setshstrndx elfx_update_shstrndx
@@ -115,7 +136,7 @@ namespace amd {
FileImage::~FileImage()
{
if (d >= 0) { amd::hsa::CloseTempFile(d); }
if (d != -1) { CloseTemp(d); }
}
bool FileImage::error(const char* msg)
@@ -153,8 +174,8 @@ namespace amd {
bool FileImage::create()
{
d = amd::hsa::OpenTempFile("amdelf");
if (d < 0) { return error("Failed to open temporary file for elf image"); }
d = OpenTemp("amdelf");
if (d == -1) { return error("Failed to open temporary file for elf image"); }
return true;
}
+33 -46
Просмотреть файл
@@ -122,60 +122,30 @@ namespace code {
hsa_status_t Symbol::GetInfo(hsa_code_symbol_info_t attribute, void *value)
{
assert(value);
std::string name = Name();
switch (attribute) {
case HSA_CODE_SYMBOL_INFO_TYPE: {
*((hsa_symbol_kind_t*)value) = Kind();
break;
}
case HSA_CODE_SYMBOL_INFO_NAME_LENGTH:
case HSA_CODE_SYMBOL_INFO_NAME_LENGTH: {
*((uint32_t*)value) = GetSymbolName().size();
break;
}
case HSA_CODE_SYMBOL_INFO_NAME: {
std::string matter = "";
switch (Linkage()) {
case HSA_SYMBOL_LINKAGE_PROGRAM:
assert(name.rfind(":") == std::string::npos);
matter = name;
break;
case HSA_SYMBOL_LINKAGE_MODULE:
assert(name.rfind(":") != std::string::npos);
matter = name.substr(name.rfind(":") + 1);
break;
default:
assert(!"Unsupported linkage in Symbol::GetInfo");
return HSA_STATUS_ERROR;
}
if (attribute == HSA_CODE_SYMBOL_INFO_NAME_LENGTH) {
*((uint32_t*) value) = matter.size() + 1;
} else {
memset(value, 0x0, matter.size() + 1);
memcpy(value, matter.c_str(), matter.size());
}
std::string SymbolName = GetSymbolName();
memset(value, 0x0, SymbolName.size());
memcpy(value, SymbolName.c_str(), SymbolName.size());
break;
}
case HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH: {
*((uint32_t*)value) = GetModuleName().size();
break;
}
case HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH:
case HSA_CODE_SYMBOL_INFO_MODULE_NAME: {
switch (Linkage()) {
case HSA_SYMBOL_LINKAGE_PROGRAM:
if (attribute == HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH) {
*((uint32_t*) value) = 0;
}
break;
case HSA_SYMBOL_LINKAGE_MODULE: {
assert(name.find(":") != std::string::npos);
std::string matter = name.substr(0, name.find(":"));
if (attribute == HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH) {
*((uint32_t*) value) = matter.length() + 1;
} else {
memset(value, 0x0, matter.size() + 1);
memcpy(value, matter.c_str(), matter.length());
((char*)value)[matter.size() + 1] = '\0';
}
break;
}
default:
assert(!"Unsupported linkage in Symbol::GetInfo");
return HSA_STATUS_ERROR;
}
std::string ModuleName = GetModuleName();
memset(value, 0x0, ModuleName.size());
memcpy(value, ModuleName.c_str(), ModuleName.size());
break;
}
case HSA_CODE_SYMBOL_INFO_LINKAGE: {
@@ -193,6 +163,18 @@ namespace code {
return HSA_STATUS_SUCCESS;
}
std::string Symbol::GetModuleName() const {
std::string FullName = Name();
return FullName.rfind(":") != std::string::npos ?
FullName.substr(0, FullName.find(":")) : "";
}
std::string Symbol::GetSymbolName() const {
std::string FullName = Name();
return FullName.rfind(":") != std::string::npos ?
FullName.substr(FullName.rfind(":") + 1) : FullName;
}
hsa_code_symbol_t Symbol::ToHandle(Symbol* sym)
{
hsa_code_symbol_t s;
@@ -994,6 +976,7 @@ namespace code {
PrintSymbols(out);
out << std::endl;
PrintMachineCode(out);
out << std::endl;
out << "AMD HSA Code Object End" << std::endl;
}
@@ -1250,7 +1233,7 @@ namespace code {
} else if (major_version == 8) {
asic = "VI";
} else if (major_version == 9) {
asic = "GREENLAND";
asic = "GFX9";
} else {
assert(!"unknown compute capability");
}
@@ -1522,11 +1505,15 @@ namespace code {
bool AmdHsaCode::PullElfV2()
{
Segment* note = NULL;
for (size_t i = 0; i < img->segmentCount(); ++i) {
Segment* s = img->segment(i);
if (s->type() == PT_LOAD) {
dataSegments.push_back(s);
}
else if (s->type() == PT_NOTE && s->align() >= 4) {
note = s;
}
}
for (size_t i = 0; i < img->sectionCount(); ++i) {
Section* sec = img->section(i);
+42 -1
Просмотреть файл
@@ -222,6 +222,47 @@ void ChoiceOption::PrintHelp(HelpPrinter& printer) const {
printer.PrintUsage(usage).PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// PrefixOption. //
//===----------------------------------------------------------------------===//
bool PrefixOption::IsValid() const {
return (0 < name_.size()) && (name_.find(':') == std::string::npos);
}
std::string::size_type PrefixOption::FindPrefix(const std::string& token) const {
auto prefix = name_ + ':';
return token.find(prefix);
}
bool PrefixOption::Accept(const std::string& token) const {
return
(token.compare(0, name_.length(), name_) == 0) &&
token.length() > name_.length() &&
token[name_.length()] == ':';
}
bool PrefixOption::ProcessTokens(std::list<std::string> &tokens) {
assert(1 <= tokens.size());
assert(Accept(tokens.front()) && "option name is mismatched");
std::string value = tokens.front(); tokens.pop_front();
value = value.substr(name_.length() + 1);
for (const auto& token: tokens) {
value += '=';
value += token;
}
tokens.clear();
values_.push_back(value);
is_set_ = true;
return true;
}
void PrefixOption::PrintHelp(HelpPrinter& printer) const {
printer.PrintUsage("-" + name_ + ":[value]").PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// OptionParser. //
//===----------------------------------------------------------------------===//
@@ -230,7 +271,7 @@ OptionParser::FindOption(const std::string& name) {
std::vector<OptionBase*>::iterator it = options_.begin();
std::vector<OptionBase*>::iterator end = options_.end();
for (; it != end; ++it) {
if ((*it)->name() == name) {
if ((*it)->Accept(name)) {
return it;
}
}
+37 -1
Просмотреть файл
@@ -152,7 +152,7 @@ public:
return is_set_;
}
bool IsValid() const {
virtual bool IsValid() const {
return 0 < name_.size();
}
@@ -166,6 +166,7 @@ protected:
error_(&error) {}
virtual void PrintHelp(HelpPrinter& printer) const = 0;
virtual bool Accept(const std::string& name) const { return name_ == name; }
const std::string name_;
const std::string help_;
@@ -393,6 +394,41 @@ private:
}
};
//===----------------------------------------------------------------------===//
// PrefixOption. //
//===----------------------------------------------------------------------===//
class PrefixOption final: public OptionBase {
public:
PrefixOption(const std::string& prefix,
const std::string& help = "",
std::ostream& error = std::cerr)
: OptionBase(prefix, help, error) {}
~PrefixOption() {}
const std::vector<std::string>& values() const {
return values_;
}
bool IsValid() const override;
protected:
void PrintHelp(HelpPrinter& printer) const override;
bool Accept(const std::string& token) const override;
private:
/// @brief Not copy-constructible.
PrefixOption(const PrefixOption&);
/// @brief Not copy-assignable.
PrefixOption& operator =(const PrefixOption&);
bool ProcessTokens(std::list<std::string> &tokens);
std::string::size_type FindPrefix(const std::string& token) const;
std::vector<std::string> values_;
};
//===----------------------------------------------------------------------===//
// OptionParser. //
//===----------------------------------------------------------------------===//
+78 -66
Просмотреть файл
@@ -72,6 +72,7 @@ public:
const amd::options::NoArgOption* DumpExec() const { return &dump_exec; }
const amd::options::NoArgOption* DumpAll() const { return &dump_all; }
const amd::options::ValueOption<std::string>* DumpDir() const { return &dump_dir; }
const amd::options::PrefixOption* Substitute() const { return &substitute; }
bool ParseOptions(const std::string& options);
void Reset();
@@ -90,6 +91,7 @@ private:
amd::options::NoArgOption dump_exec;
amd::options::NoArgOption dump_all;
amd::options::ValueOption<std::string> dump_dir;
amd::options::PrefixOption substitute;
amd::options::OptionParser option_parser;
};
@@ -100,6 +102,7 @@ LoaderOptions::LoaderOptions(std::ostream& error) :
dump_exec("dump-exec", "Dump executable to text file"),
dump_all("dump-all", "Dump all finalizer input and output (as above)"),
dump_dir("dump-dir", "Dump directory"),
substitute("substitute", "Substitute code object with given index or index range on loading from file"),
option_parser(false, error)
{
option_parser.AddOption(&help);
@@ -108,17 +111,21 @@ LoaderOptions::LoaderOptions(std::ostream& error) :
option_parser.AddOption(&dump_exec);
option_parser.AddOption(&dump_all);
option_parser.AddOption(&dump_dir);
option_parser.AddOption(&substitute);
}
bool LoaderOptions::ParseOptions(const std::string& options) {
bool LoaderOptions::ParseOptions(const std::string& options)
{
return option_parser.ParseOptions(options.c_str());
}
void LoaderOptions::Reset() {
void LoaderOptions::Reset()
{
option_parser.Reset();
}
void LoaderOptions::PrintHelp(std::ostream& out) const {
void LoaderOptions::PrintHelp(std::ostream& out) const
{
option_parser.PrintHelp(out);
}
@@ -232,6 +239,11 @@ uint64_t AmdHsaCodeLoader::FindHostAddress(uint64_t device_address)
return 0;
}
void AmdHsaCodeLoader::PrintHelp(std::ostream& out)
{
LoaderOptions().PrintHelp(out);
}
void AmdHsaCodeLoader::EnableReadOnlyMode()
{
rw_lock_.ReaderLock();
@@ -306,62 +318,21 @@ bool SymbolImpl::GetInfo(hsa_symbol_info32_t symbol_info, void *value) {
break;
}
case HSA_CODE_SYMBOL_INFO_NAME_LENGTH: {
std::string matter = "";
if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) {
assert(name.rfind(":") == std::string::npos);
matter = name;
} else {
assert(name.rfind(":") != std::string::npos);
matter = name.substr(name.rfind(":") + 1);
}
*((uint32_t*)value) = matter.size() + 1;
*((uint32_t*)value) = symbol_name.size();
break;
}
case HSA_CODE_SYMBOL_INFO_NAME: {
std::string matter = "";
if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) {
assert(name.rfind(":") == std::string::npos);
matter = name;
} else {
assert(name.rfind(":") != std::string::npos);
matter = name.substr(name.rfind(":") + 1);
}
memset(value, 0x0, matter.size() + 1);
memcpy(value, matter.c_str(), matter.size());
memset(value, 0x0, symbol_name.size());
memcpy(value, symbol_name.c_str(), symbol_name.size());
break;
}
case HSA_CODE_SYMBOL_INFO_MODULE_NAME_LENGTH: {
std::string matter = "";
if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) {
assert(name.find(":") == std::string::npos);
*((uint32_t*)value) = 0;
return true;
}
assert(name.find(":") != std::string::npos);
matter = name.substr(0, name.find(":"));
*((uint32_t*)value) = matter.size() + 1;
*((uint32_t*)value) = module_name.size();
break;
}
case HSA_CODE_SYMBOL_INFO_MODULE_NAME: {
std::string matter = "";
if (linkage == HSA_SYMBOL_LINKAGE_PROGRAM) {
assert(name.find(":") == std::string::npos);
return true;
}
assert(name.find(":") != std::string::npos);
matter = name.substr(0, name.find(":"));
memset(value, 0x0, matter.size() + 1);
memcpy(value, matter.c_str(), matter.size());
memset(value, 0x0, module_name.size());
memcpy(value, module_name.c_str(), module_name.size());
break;
}
case HSA_CODE_SYMBOL_INFO_LINKAGE: {
@@ -698,6 +669,8 @@ hsa_status_t ExecutableImpl::DefineProgramExternalVariable(
program_symbols_.insert(
std::make_pair(std::string(name),
new VariableSymbol(true,
"", // Only program linkage symbols can be
// defined.
std::string(name),
HSA_SYMBOL_LINKAGE_PROGRAM,
true,
@@ -732,6 +705,8 @@ hsa_status_t ExecutableImpl::DefineAgentExternalVariable(
auto insert_status = agent_symbols_.insert(
std::make_pair(std::make_pair(std::string(name), agent),
new VariableSymbol(true,
"", // Only program linkage symbols can be
// defined.
std::string(name),
HSA_SYMBOL_LINKAGE_PROGRAM,
true,
@@ -997,7 +972,7 @@ hsa_status_t ExecutableImpl::GetInfo(
return HSA_STATUS_SUCCESS;
}
static uint32_t NextLoaderDumpNum()
static uint32_t NextCodeObjectNum()
{
static std::atomic_uint_fast32_t dumpN(1);
return dumpN++;
@@ -1034,27 +1009,62 @@ hsa_status_t ExecutableImpl::LoadCodeObject(
return HSA_STATUS_ERROR;
}
code.reset(new code::AmdHsaCode());
typedef std::tuple<uint32_t, uint32_t, std::string> Substitute;
std::vector<Substitute> substitutes;
if (!code->InitAsHandle(code_object)) {
return HSA_STATUS_ERROR_INVALID_CODE_OBJECT;
for (const std::string& s : loaderOptions.Substitute()->values()) {
std::string::size_type vi = s.find('=');
if (vi == std::string::npos) { return HSA_STATUS_ERROR; }
std::string value = s.substr(vi + 1);
std::string range = s.substr(0, vi);
std::string::size_type mi = range.find('-');
uint32_t n1 = UINT32_MAX, n2 = UINT32_MAX;
if (mi != std::string::npos) {
std::string s1, s2;
s1 = range.substr(0, mi - 1);
s2 = range.substr(mi + 1);
std::istringstream is1(s1); is1 >> n1;
std::istringstream is2(s2); is2 >> n2;
}
else {
std::istringstream is(range); is >> n1;
n2 = n1;
}
substitutes.push_back(std::make_tuple(n1, n2, value));
}
uint32_t dumpNum = 0;
if (loaderOptions.DumpAll()->is_set() ||
loaderOptions.DumpExec()->is_set() ||
loaderOptions.DumpCode()->is_set() ||
loaderOptions.DumpIsa()->is_set()) {
dumpNum = NextLoaderDumpNum();
uint32_t codeNum = NextCodeObjectNum();
code.reset(new code::AmdHsaCode());
std::string substituteFileName;
for (const Substitute& ss : substitutes) {
if (codeNum >= std::get<0>(ss) && codeNum <= std::get<1>(ss)) {
substituteFileName = std::get<2>(ss);
break;
}
}
std::vector<char> buffer;
if (substituteFileName.empty()) {
if (!code->InitAsHandle(code_object)) {
return HSA_STATUS_ERROR_INVALID_CODE_OBJECT;
}
} else {
if (!ReadFileIntoBuffer(substituteFileName, buffer)) {
return HSA_STATUS_ERROR_INVALID_CODE_OBJECT;
}
if (!code->InitAsBuffer(&buffer[0], buffer.size())) {
return HSA_STATUS_ERROR_INVALID_CODE_OBJECT;
}
}
if (loaderOptions.DumpAll()->is_set() || loaderOptions.DumpCode()->is_set()) {
if (!code->SaveToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "hsaco", dumpNum))) {
if (!code->SaveToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "hsaco", codeNum))) {
// Ignore error.
}
}
if (loaderOptions.DumpAll()->is_set() || loaderOptions.DumpIsa()->is_set()) {
if (!code->PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "isa", dumpNum))) {
if (!code->PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "isa", codeNum))) {
// Ignore error.
}
}
@@ -1105,7 +1115,7 @@ hsa_status_t ExecutableImpl::LoadCodeObject(
code.reset();
if (loaderOptions.DumpAll()->is_set() || loaderOptions.DumpExec()->is_set()) {
if (!PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "exec", dumpNum))) {
if (!PrintToFile(amd::hsa::DumpFileName(loaderOptions.DumpDir()->value(), LOADER_DUMP_PREFIX, "exec", codeNum))) {
// Ignore error.
}
}
@@ -1240,7 +1250,8 @@ hsa_status_t ExecutableImpl::LoadDefinitionSymbol(hsa_agent_t agent,
SymbolImpl *symbol = nullptr;
if (sym->IsVariableSymbol()) {
symbol = new VariableSymbol(true,
sym->Name(),
sym->GetModuleName(),
sym->GetSymbolName(),
sym->Linkage(),
true, // sym->IsDefinition()
sym->Allocation(),
@@ -1273,7 +1284,8 @@ hsa_status_t ExecutableImpl::LoadDefinitionSymbol(hsa_agent_t agent,
size = sym->GetSection()->size() - sym->SectionOffset();
}
KernelSymbol *kernel_symbol = new KernelSymbol(true,
sym->Name(),
sym->GetModuleName(),
sym->GetSymbolName(),
sym->Linkage(),
true, // sym->IsDefinition()
kernarg_segment_size,
@@ -1286,7 +1298,7 @@ hsa_status_t ExecutableImpl::LoadDefinitionSymbol(hsa_agent_t agent,
address);
kernel_symbol->debug_info.elf_raw = code->ElfData();
kernel_symbol->debug_info.elf_size = code->ElfSize();
kernel_symbol->debug_info.kernel_name = kernel_symbol->name.c_str();
kernel_symbol->debug_info.kernel_name = kernel_symbol->full_name.c_str();
kernel_symbol->debug_info.owning_segment = (void*)SymbolSegment(agent, sym)->Address(sym->GetSection()->addr());
symbol = kernel_symbol;
+19 -8
Просмотреть файл
@@ -88,7 +88,8 @@ public:
bool is_loaded;
hsa_symbol_kind_t kind;
std::string name;
std::string module_name;
std::string symbol_name;
hsa_symbol_linkage_t linkage;
bool is_definition;
uint64_t address;
@@ -101,18 +102,20 @@ public:
protected:
SymbolImpl(const bool &_is_loaded,
const hsa_symbol_kind_t &_kind,
const std::string &_name,
const std::string &_module_name,
const std::string &_symbol_name,
const hsa_symbol_linkage_t &_linkage,
const bool &_is_definition,
const uint64_t &_address = 0)
: is_loaded(_is_loaded)
, kind(_kind)
, name(_name)
, module_name(_module_name)
, symbol_name(_symbol_name)
, linkage(_linkage)
, is_definition(_is_definition)
, address(_address) {}
virtual bool GetInfo(hsa_symbol_info32_t symbol_info, void *value) override;
virtual bool GetInfo(hsa_symbol_info32_t symbol_info, void *value);
private:
SymbolImpl(const SymbolImpl &s);
@@ -126,7 +129,8 @@ private:
class KernelSymbol final: public SymbolImpl {
public:
KernelSymbol(const bool &_is_loaded,
const std::string &_name,
const std::string &_module_name,
const std::string &_symbol_name,
const hsa_symbol_linkage_t &_linkage,
const bool &_is_definition,
const uint32_t &_kernarg_segment_size,
@@ -139,10 +143,12 @@ public:
const uint64_t &_address = 0)
: SymbolImpl(_is_loaded,
HSA_SYMBOL_KIND_KERNEL,
_name,
_module_name,
_symbol_name,
_linkage,
_is_definition,
_address)
, full_name(_module_name.empty() ? _symbol_name : _module_name + "::" + _symbol_name)
, kernarg_segment_size(_kernarg_segment_size)
, kernarg_segment_alignment(_kernarg_segment_alignment)
, group_segment_size(_group_segment_size)
@@ -155,6 +161,7 @@ public:
bool GetInfo(hsa_symbol_info32_t symbol_info, void *value);
std::string full_name;
uint32_t kernarg_segment_size;
uint32_t kernarg_segment_alignment;
uint32_t group_segment_size;
@@ -176,7 +183,8 @@ private:
class VariableSymbol final: public SymbolImpl {
public:
VariableSymbol(const bool &_is_loaded,
const std::string &_name,
const std::string &_module_name,
const std::string &_symbol_name,
const hsa_symbol_linkage_t &_linkage,
const bool &_is_definition,
const hsa_variable_allocation_t &_allocation,
@@ -188,7 +196,8 @@ public:
const uint64_t &_address = 0)
: SymbolImpl(_is_loaded,
HSA_SYMBOL_KIND_VARIABLE,
_name,
_module_name,
_symbol_name,
_linkage,
_is_definition,
_address)
@@ -526,6 +535,8 @@ public:
uint64_t FindHostAddress(uint64_t device_address) override;
void PrintHelp(std::ostream& out) override;
void EnableReadOnlyMode();
void DisableReadOnlyMode();
};