From a2aef882e9d07e6592da79bdd78664254cf551a0 Mon Sep 17 00:00:00 2001 From: David McFarland Date: Tue, 7 May 2024 16:21:57 -0300 Subject: [PATCH] Add support for 64-bit elfs from atidxx This is what I get using the latest drivers (24.4.1) on Windows. --- renderdoc/driver/ihv/amd/amd_isa_win32.cpp | 156 +++++----- .../driver/ihv/amd/official/RGA/elf/elf64.h | 269 ++++++++++++++++++ 2 files changed, 356 insertions(+), 69 deletions(-) create mode 100644 renderdoc/driver/ihv/amd/official/RGA/elf/elf64.h diff --git a/renderdoc/driver/ihv/amd/amd_isa_win32.cpp b/renderdoc/driver/ihv/amd/amd_isa_win32.cpp index 73b0bd3aa..48585b014 100644 --- a/renderdoc/driver/ihv/amd/amd_isa_win32.cpp +++ b/renderdoc/driver/ihv/amd/amd_isa_win32.cpp @@ -28,6 +28,7 @@ #include "core/plugins.h" #include "official/RGA/Common/AmdDxGsaCompile.h" #include "official/RGA/elf/elf32.h" +#include "official/RGA/elf/elf64.h" #include "amd_isa_devices.h" #if ENABLED(RDOC_X64) @@ -69,6 +70,91 @@ HRESULT SafelyCompile(PfnAmdDxGsaCompileShader compileShader, AmdDxGsaCompileSha return ret; } +template +static rdcstr ParseElf(const Elf_Ehdr *elfHeader, bool amdil, const rdcstr &target) +{ + rdcstr ret; + + const uint8_t *elf = (const uint8_t *)elfHeader; + + const Elf_Shdr *strtab = + (const Elf_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf_Shdr) * elfHeader->e_shstrndx); + + const uint8_t *strtabData = elf + strtab->sh_offset; + + const AmdDxGsaCompileStats *stats = NULL; + + for(int section = 1; section < elfHeader->e_shnum; section++) + { + if(section == elfHeader->e_shstrndx) + continue; + + const Elf_Shdr *sectHeader = + (const Elf_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf_Shdr) * section); + + const char *name = (const char *)(strtabData + sectHeader->sh_name); + + const uint8_t *data = elf + sectHeader->sh_offset; + + if(!strcmp(name, ".stats")) + { + stats = (const AmdDxGsaCompileStats *)data; + } + else if(amdil && !strcmp(name, ".amdil_disassembly")) + { + ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size); + while(ret.back() == '\0') + ret.pop_back(); + } + else if(!amdil && !strcmp(name, ".disassembly")) + { + ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size); + while(ret.back() == '\0') + ret.pop_back(); + } + } + + if(stats && !amdil) + { + ret.insert(0, StringFormat::Fmt( + R"(; -------- Statistics --------------------- +; SGPRs: %u out of %u used +; VGPRs: %u out of %u used +; LDS: %u out of %u bytes used +; %u bytes scratch space used +; Instructions: %u ALU, %u Control Flow, %u TFETCH + +)", + stats->numSgprsUsed, stats->availableSgprs, stats->numVgprsUsed, + stats->availableVgprs, stats->usedLdsBytes, stats->availableLdsBytes, + stats->usedScratchBytes, stats->numAluInst, stats->numControlFlowInst, + stats->numTfetchInst)); + } + + ret.insert(0, StringFormat::Fmt("; Disassembly for %s\n\n", target.c_str())); + + return ret; +} + +static rdcstr ParseElf(const uint8_t *elf, bool amdil, const rdcstr &target) +{ + const Elf32_Ehdr *elf32Header = (const Elf32_Ehdr *)elf; + + // minimal code to extract data from ELF. We assume the ELF we got back is well-formed. + if(IS_ELF(*elf32Header)) + { + if(elf32Header->e_ident[EI_CLASS] == ELFCLASS32) + { + return ParseElf(elf32Header, amdil, target); + } + else if(elf32Header->e_ident[EI_CLASS] == ELFCLASS64) + { + return ParseElf((const Elf64_Ehdr *)elf, amdil, target); + } + } + return "; Invalid ELF file generated"; +} + rdcstr DisassembleDXBC(const bytebuf &shaderBytes, const rdcstr &target) { HMODULE mod = GetAMDModule(); @@ -205,75 +291,7 @@ rdcstr DisassembleDXBC(const bytebuf &shaderBytes, const rdcstr &target) return "; Failed to disassemble shader"; } - const uint8_t *elf = (const uint8_t *)out.pShaderBinary; - - const Elf32_Ehdr *elfHeader = (const Elf32_Ehdr *)elf; - - rdcstr ret; - - // minimal code to extract data from ELF. We assume the ELF we got back is well-formed. - if(IS_ELF(*elfHeader) && elfHeader->e_ident[EI_CLASS] == ELFCLASS32) - { - const Elf32_Shdr *strtab = - (const Elf32_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf32_Shdr) * elfHeader->e_shstrndx); - - const uint8_t *strtabData = elf + strtab->sh_offset; - - const AmdDxGsaCompileStats *stats = NULL; - - for(int section = 1; section < elfHeader->e_shnum; section++) - { - if(section == elfHeader->e_shstrndx) - continue; - - const Elf32_Shdr *sectHeader = - (const Elf32_Shdr *)(elf + elfHeader->e_shoff + sizeof(Elf32_Shdr) * section); - - const char *name = (const char *)(strtabData + sectHeader->sh_name); - - const uint8_t *data = elf + sectHeader->sh_offset; - - if(!strcmp(name, ".stats")) - { - stats = (const AmdDxGsaCompileStats *)data; - } - else if(amdil && !strcmp(name, ".amdil_disassembly")) - { - ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size); - while(ret.back() == '\0') - ret.pop_back(); - } - else if(!amdil && !strcmp(name, ".disassembly")) - { - ret.insert(0, (const char *)data, (size_t)sectHeader->sh_size); - while(ret.back() == '\0') - ret.pop_back(); - } - } - - if(stats && !amdil) - { - ret.insert(0, StringFormat::Fmt( - R"(; -------- Statistics --------------------- -; SGPRs: %u out of %u used -; VGPRs: %u out of %u used -; LDS: %u out of %u bytes used -; %u bytes scratch space used -; Instructions: %u ALU, %u Control Flow, %u TFETCH - -)", - stats->numSgprsUsed, stats->availableSgprs, stats->numVgprsUsed, - stats->availableVgprs, stats->usedLdsBytes, stats->availableLdsBytes, - stats->usedScratchBytes, stats->numAluInst, stats->numControlFlowInst, - stats->numTfetchInst)); - } - - ret.insert(0, StringFormat::Fmt("; Disassembly for %s\n\n", target.c_str())); - } - else - { - ret = "; Invalid ELF file generated"; - } + const rdcstr ret = ParseElf((const uint8_t *)out.pShaderBinary, amdil, target); freeShader(out.pShaderBinary); diff --git a/renderdoc/driver/ihv/amd/official/RGA/elf/elf64.h b/renderdoc/driver/ihv/amd/official/RGA/elf/elf64.h new file mode 100644 index 000000000..048636d64 --- /dev/null +++ b/renderdoc/driver/ihv/amd/official/RGA/elf/elf64.h @@ -0,0 +1,269 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1996-1998 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_ELF64_H_ +#define _SYS_ELF64_H_ 1 + +#include "elf_common.h" + +/* + * ELF definitions common to all 64-bit architectures. + */ + +typedef uint64_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef int64_t Elf64_Sxword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Lword; +typedef uint64_t Elf64_Xword; + +/* + * Types of dynamic symbol hash table bucket and chain elements. + * + * This is inconsistent among 64 bit architectures, so a machine dependent + * typedef is required. + */ + +typedef Elf64_Word Elf64_Hashelt; + +/* Non-standard class-dependent datatype used for abstraction. */ +typedef Elf64_Xword Elf64_Size; +typedef Elf64_Sxword Elf64_Ssize; + +/* + * ELF header. + */ + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* File identification. */ + Elf64_Half e_type; /* File type. */ + Elf64_Half e_machine; /* Machine architecture. */ + Elf64_Word e_version; /* ELF format version. */ + Elf64_Addr e_entry; /* Entry point. */ + Elf64_Off e_phoff; /* Program header file offset. */ + Elf64_Off e_shoff; /* Section header file offset. */ + Elf64_Word e_flags; /* Architecture-specific flags. */ + Elf64_Half e_ehsize; /* Size of ELF header in bytes. */ + Elf64_Half e_phentsize; /* Size of program header entry. */ + Elf64_Half e_phnum; /* Number of program header entries. */ + Elf64_Half e_shentsize; /* Size of section header entry. */ + Elf64_Half e_shnum; /* Number of section header entries. */ + Elf64_Half e_shstrndx; /* Section name strings section. */ +} Elf64_Ehdr; + +/* + * Shared object information, found in SHT_MIPS_LIBLIST. + */ + +typedef struct { + Elf64_Word l_name; /* The name of a shared object. */ + Elf64_Word l_time_stamp; /* 64-bit timestamp. */ + Elf64_Word l_checksum; /* Checksum of visible symbols, sizes. */ + Elf64_Word l_version; /* Interface version string index. */ + Elf64_Word l_flags; /* Flags (LL_*). */ +} Elf64_Lib; + +/* + * Section header. + */ + +typedef struct { + Elf64_Word sh_name; /* Section name (index into the + section header string table). */ + Elf64_Word sh_type; /* Section type. */ + Elf64_Xword sh_flags; /* Section flags. */ + Elf64_Addr sh_addr; /* Address in memory image. */ + Elf64_Off sh_offset; /* Offset in file. */ + Elf64_Xword sh_size; /* Size in bytes. */ + Elf64_Word sh_link; /* Index of a related section. */ + Elf64_Word sh_info; /* Depends on section type. */ + Elf64_Xword sh_addralign; /* Alignment in bytes. */ + Elf64_Xword sh_entsize; /* Size of each entry in section. */ +} Elf64_Shdr; + +/* + * Program header. + */ + +typedef struct { + Elf64_Word p_type; /* Entry type. */ + Elf64_Word p_flags; /* Access permission flags. */ + Elf64_Off p_offset; /* File offset of contents. */ + Elf64_Addr p_vaddr; /* Virtual address in memory image. */ + Elf64_Addr p_paddr; /* Physical address (not used). */ + Elf64_Xword p_filesz; /* Size of contents in file. */ + Elf64_Xword p_memsz; /* Size of contents in memory. */ + Elf64_Xword p_align; /* Alignment in memory and file. */ +} Elf64_Phdr; + +/* + * Dynamic structure. The ".dynamic" section contains an array of them. + */ + +typedef struct { + Elf64_Sxword d_tag; /* Entry type. */ + union { + Elf64_Xword d_val; /* Integer value. */ + Elf64_Addr d_ptr; /* Address value. */ + } d_un; +} Elf64_Dyn; + +/* + * Relocation entries. + */ + +/* Relocations that don't need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Relocation type and symbol index. */ +} Elf64_Rel; + +/* Relocations that need an addend field. */ +typedef struct { + Elf64_Addr r_offset; /* Location to be relocated. */ + Elf64_Xword r_info; /* Relocation type and symbol index. */ + Elf64_Sxword r_addend; /* Addend. */ +} Elf64_Rela; + +/* Macros for accessing the fields of r_info. */ +#define ELF64_R_SYM(info) ((info) >> 32) +#define ELF64_R_TYPE(info) ((info) & 0xffffffffL) + +/* Macro for constructing r_info from field values. */ +#define ELF64_R_INFO(sym, type) (((sym) << 32) + ((type) & 0xffffffffL)) + +#define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info)<<32)>>40) +#define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info)<<56)>>56) +#define ELF64_R_TYPE_INFO(data, type) \ + (((Elf64_Xword)(data)<<8)+(Elf64_Xword)(type)) + +typedef Elf64_Xword Elf64_Relr; + +/* + * Note entry header + */ +typedef Elf_Note Elf64_Nhdr; + +/* + * Move entry + */ +typedef struct { + Elf64_Lword m_value; /* symbol value */ + Elf64_Xword m_info; /* size + index */ + Elf64_Xword m_poffset; /* symbol offset */ + Elf64_Half m_repeat; /* repeat count */ + Elf64_Half m_stride; /* stride info */ +} Elf64_Move; + +#define ELF64_M_SYM(info) ((info)>>8) +#define ELF64_M_SIZE(info) ((unsigned char)(info)) +#define ELF64_M_INFO(sym, size) (((sym)<<8)+(unsigned char)(size)) + +/* + * Hardware/Software capabilities entry + */ +typedef struct { + Elf64_Xword c_tag; /* how to interpret value */ + union { + Elf64_Xword c_val; + Elf64_Addr c_ptr; + } c_un; +} Elf64_Cap; + +/* + * Symbol table entries. + */ + +typedef struct { + Elf64_Word st_name; /* String table index of name. */ + unsigned char st_info; /* Type and binding information. */ + unsigned char st_other; /* Reserved (not used). */ + Elf64_Half st_shndx; /* Section index of symbol. */ + Elf64_Addr st_value; /* Symbol value. */ + Elf64_Xword st_size; /* Size of associated object. */ +} Elf64_Sym; + +/* Macros for accessing the fields of st_info. */ +#define ELF64_ST_BIND(info) ((info) >> 4) +#define ELF64_ST_TYPE(info) ((info) & 0xf) + +/* Macro for constructing st_info from field values. */ +#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Macro for accessing the fields of st_other. */ +#define ELF64_ST_VISIBILITY(oth) ((oth) & 0x3) + +/* Structures used by Sun & GNU-style symbol versioning. */ +typedef struct { + Elf64_Half vd_version; + Elf64_Half vd_flags; + Elf64_Half vd_ndx; + Elf64_Half vd_cnt; + Elf64_Word vd_hash; + Elf64_Word vd_aux; + Elf64_Word vd_next; +} Elf64_Verdef; + +typedef struct { + Elf64_Word vda_name; + Elf64_Word vda_next; +} Elf64_Verdaux; + +typedef struct { + Elf64_Half vn_version; + Elf64_Half vn_cnt; + Elf64_Word vn_file; + Elf64_Word vn_aux; + Elf64_Word vn_next; +} Elf64_Verneed; + +typedef struct { + Elf64_Word vna_hash; + Elf64_Half vna_flags; + Elf64_Half vna_other; + Elf64_Word vna_name; + Elf64_Word vna_next; +} Elf64_Vernaux; + +typedef Elf64_Half Elf64_Versym; + +typedef struct { + Elf64_Half si_boundto; /* direct bindings - symbol bound to */ + Elf64_Half si_flags; /* per symbol flags */ +} Elf64_Syminfo; + +typedef struct { + Elf64_Word ch_type; + Elf64_Word ch_reserved; + Elf64_Xword ch_size; + Elf64_Xword ch_addralign; +} Elf64_Chdr; + +#endif /* !_SYS_ELF64_H_ */