25#include <amd_comgr/amd_comgr.h>
26#include <hsa/amd_hsa_elf.h>
43#include <unordered_map>
46#define THROW_COMGR(call) \
47 if(amd_comgr_status_s status = call) \
49 const char* reason = ""; \
50 amd_comgr_status_string(status, &reason); \
51 std::cerr << __FILE__ << ':' << __LINE__ << " code: " << status << " failed: " << reason \
53 throw std::exception(); \
56#define RETURN_COMGR(call) \
57 if(amd_comgr_status_s status = call) \
59 const char* reason = ""; \
60 amd_comgr_status_string(status, &reason); \
61 std::cerr << __FILE__ << ':' << __LINE__ << " code: " << status << " failed: " << reason \
63 return AMD_COMGR_STATUS_ERROR; \
77 CodeObjectBinary(std::string _uri)
78 : m_uri(
std::move(_uri))
80 const std::string protocol_delim{
"://"};
82 size_t protocol_end = m_uri.find(protocol_delim);
83 std::string protocol = m_uri.substr(0, protocol_end);
84 protocol_end += protocol_delim.length();
86 std::transform(protocol.begin(), protocol.end(), protocol.begin(), [](
unsigned char c) {
87 return std::tolower(c);
91 size_t path_end = m_uri.find_first_of(
"#?", protocol_end);
92 if(path_end != std::string::npos)
94 path = m_uri.substr(protocol_end, path_end++ - protocol_end);
98 path = m_uri.substr(protocol_end);
102 std::string decoded_path;
103 decoded_path.reserve(path.length());
104 for(
size_t i = 0; i < path.length(); ++i)
106 if(path[i] ==
'%' && std::isxdigit(path[i + 1]) != 0 && std::isxdigit(path[i + 2]) != 0)
108 decoded_path += std::stoi(path.substr(i + 1, 2),
nullptr, 16);
113 decoded_path += path[i];
118 std::vector<std::string> tokens;
119 size_t pos, last = path_end;
120 while((pos = m_uri.find(
'&', last)) != std::string::npos)
122 tokens.emplace_back(m_uri.substr(last, pos - last));
125 if(last != std::string::npos)
127 tokens.emplace_back(m_uri.substr(last));
131 std::unordered_map<std::string, std::string> params;
132 std::for_each(tokens.begin(), tokens.end(), [&](std::string& token) {
133 size_t delim = token.find(
'=');
134 if(delim != std::string::npos)
136 params.emplace(token.substr(0, delim), token.substr(delim + 1));
140 buffer = std::vector<char>{};
144 if(
auto offset_it = params.find(
"offset"); offset_it != params.end())
146 offset = std::stoul(offset_it->second,
nullptr, 0);
149 if(
auto size_it = params.find(
"size"); size_it != params.end())
151 if((size = std::stoul(size_it->second,
nullptr, 0)) == 0)
return;
154 if(protocol ==
"memory")
throw std::runtime_error(protocol +
" protocol not supported!");
156 std::ifstream file(decoded_path, std::ios::in | std::ios::binary);
157 if(!file || !file.is_open())
throw std::runtime_error(
"could not open " + decoded_path);
161 file.ignore(std::numeric_limits<std::streamsize>::max());
162 size_t bytes = file.gcount();
165 if(bytes < offset)
throw std::runtime_error(
"invalid uri " + decoded_path);
167 size = bytes - offset;
170 file.seekg(offset, std::ios_base::beg);
172 file.read(buffer.data(), size);
176 std::vector<char> buffer;
184 uint64_t mem_size = 0;
187class DisassemblyInstance
190 DisassemblyInstance(
const char* codeobj_data, uint64_t codeobj_size)
192 buffer = std::vector<char>(codeobj_size, 0);
193 std::memcpy(buffer.data(), codeobj_data, codeobj_size);
195 THROW_COMGR(amd_comgr_create_data(AMD_COMGR_DATA_KIND_EXECUTABLE, &data));
196 THROW_COMGR(amd_comgr_set_data(data, buffer.size(), buffer.data()));
198 size_t isa_size = 128;
199 std::string input_isa{};
200 input_isa.resize(isa_size);
201 THROW_COMGR(amd_comgr_get_data_isa_name(data, &isa_size, input_isa.data()));
203 THROW_COMGR(amd_comgr_create_disassembly_info(
205 &DisassemblyInstance::memory_callback,
206 &DisassemblyInstance::inst_callback,
207 [](uint64_t,
void*) {},
210 ~DisassemblyInstance()
212 amd_comgr_release_data(data);
213 amd_comgr_destroy_disassembly_info(info);
216 std::pair<std::string, size_t> ReadInstruction(uint64_t faddr)
219 uint64_t addr_in_buffer =
reinterpret_cast<uint64_t
>(buffer.data()) + faddr;
222 amd_comgr_disassemble_instruction(info, addr_in_buffer, (
void*)
this, &size_read));
223 return {std::move(this->last_instruction), size_read};
226 std::map<uint64_t, SymbolInfo>& GetKernelMap()
229 THROW_COMGR(amd_comgr_iterate_symbols(data, &DisassemblyInstance::symbol_callback,
this));
234 static amd_comgr_status_t symbol_callback(amd_comgr_symbol_t symbol,
void* user_data)
236 amd_comgr_symbol_type_t type;
237 RETURN_COMGR(amd_comgr_symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_TYPE, &type));
239 if(type != AMD_COMGR_SYMBOL_TYPE_FUNC)
return AMD_COMGR_STATUS_SUCCESS;
242 uint64_t mem_size = 0;
243 uint64_t name_size = 0;
244 RETURN_COMGR(amd_comgr_symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_VALUE, &vaddr));
245 RETURN_COMGR(amd_comgr_symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_SIZE, &mem_size));
247 amd_comgr_symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_NAME_LENGTH, &name_size));
250 name.resize(name_size);
252 RETURN_COMGR(amd_comgr_symbol_get_info(symbol, AMD_COMGR_SYMBOL_INFO_NAME, name.data()));
254 DisassemblyInstance& instance = *
static_cast<DisassemblyInstance*
>(user_data);
255 std::optional<uint64_t> faddr = instance.va2fo(vaddr);
257 if(faddr) instance.symbol_map[vaddr] = {name, *faddr, vaddr, mem_size};
258 return AMD_COMGR_STATUS_SUCCESS;
261 static uint64_t memory_callback(uint64_t from,
char* to, uint64_t size,
void* user_data)
263 DisassemblyInstance& instance = *
static_cast<DisassemblyInstance*
>(user_data);
264 int64_t copysize =
reinterpret_cast<int64_t
>(instance.buffer.data()) +
265 instance.buffer.size() -
static_cast<int64_t
>(from);
266 copysize = std::min<int64_t>(size, copysize);
268 std::memcpy(to, (
char*) from, copysize);
272 static void inst_callback(
const char* instruction,
void* user_data)
274 DisassemblyInstance& instance = *
static_cast<DisassemblyInstance*
>(user_data);
276 if(!instruction)
return;
278 while(*instruction ==
'\t' || *instruction ==
' ')
280 instance.last_instruction = instruction;
283 std::optional<uint64_t> va2fo(uint64_t va)
const
286 uint64_t slicesize = 0;
289 auto status = amd_comgr_map_elf_virtual_address_to_code_object_offset(
290 data, va, &offset, &slicesize, &nobits);
292 if(status != AMD_COMGR_STATUS_SUCCESS || nobits)
298 std::vector<char> buffer{};
299 std::string last_instruction{};
300 amd_comgr_disassembly_info_t info{};
301 amd_comgr_data_t data{};
302 std::map<uint64_t, SymbolInfo> symbol_map{};