Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -60,6 +60,8 @@ #include #include +#include "../../lib/Target/AMDGPU/AMDKernelCodeT.h" + using namespace llvm; using namespace object; @@ -830,6 +832,133 @@ return false; } +class HSACodeObject { +public: + typedef ELF64LEObjectFile MyELF; + const MyELF& Obj; + + HSACodeObject(const ObjectFile *Obj_) + : Obj(*static_cast(Obj_)) {} + + std::pair> + getKernel(SymbolRef Symbol) const { + auto ElfSym = Obj.getSymbol(Symbol.getRawDataRefImpl()); + if (ElfSym->getType() != ELF::STT_AMDGPU_HSA_KERNEL) { + return decltype(this->getKernel(Symbol))(); + } + + auto ELF = Obj.getELFFile(); + auto SecBytes = *ELF->getSectionContentsAsArray( + *ELF->getSection(ElfSym->st_shndx)); + + uint64_t const Ofs = ElfSym->getValue(); + auto const C = + reinterpret_cast(SecBytes.slice(Ofs).begin()); + + auto& M = getStartMarkers(); + uint64_t const CodeStart = Ofs + C->kernel_code_entry_byte_offset; + uint64_t const CodeEnd = *std::upper_bound(M.begin(), M.end(), CodeStart); + + return std::make_pair(C, SecBytes.slice(CodeStart, CodeEnd - CodeStart)); + } + +private: + mutable SmallVector StartMarkers; + + const decltype(StartMarkers)& getStartMarkers() const; +}; + +// StartMarkers is a sorted array of every entity's begin in the code section. +// We determine an entity's ending using upper bound on this array because there'is +// no kernel code size specified by design +const decltype(HSACodeObject::StartMarkers)& +HSACodeObject::getStartMarkers() const { + if (!StartMarkers.empty()) return StartMarkers; + + auto ELF = Obj.getELFFile(); + int HsaTextSecIdx = -1; + ArrayRef SecBytes; + + for (auto& Symbol : Obj.symbols()) { + auto ElfSym = Obj.getSymbol(Symbol.getRawDataRefImpl()); + if (HsaTextSecIdx != -1 && ElfSym->st_shndx != HsaTextSecIdx) continue; + switch (ElfSym->getType()) { + case ELF::STT_AMDGPU_HSA_KERNEL: { + if (HsaTextSecIdx == -1) { + HsaTextSecIdx = ElfSym->st_shndx; + SecBytes = *ELF->getSectionContentsAsArray( + *ELF->getSection(HsaTextSecIdx)); + } + uint64_t Ofs = ElfSym->getValue(); + StartMarkers.push_back(Ofs); + auto C = reinterpret_cast( + SecBytes.slice(Ofs).begin()); + StartMarkers.push_back(Ofs + C->kernel_code_entry_byte_offset); + break; + } + default: break; + }; + } + + StartMarkers.push_back(SecBytes.size()); + array_pod_sort(StartMarkers.begin(), StartMarkers.end()); + + return StartMarkers; +} + +namespace llvm { +void dump(const amd_kernel_code_t*, raw_ostream& os, const char*); +} + +static void DisassembleHSACodeObject(const ObjectFile *Obj, + MCInstPrinter& IP, + MCDisassembler& DisAsm, + const MCSubtargetInfo& STI) { + +#ifdef NDEBUG + bool const DebugFlag = false; +#endif + + HSACodeObject CObj(Obj); + SmallString<40> Comments; + raw_svector_ostream CommentStream(Comments); + raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls(); + PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName)); + + // Disassemble symbol by symbol. + for (auto Symbol : Obj->symbols()) { + + auto Kernel = CObj.getKernel(Symbol); + if (!Kernel.first) continue; + + outs() << *Symbol.getName() << '\n'; + dump(Kernel.first, outs(), " "); + + const auto& Code = Kernel.second; + if (Code.empty()) continue; + + uint64_t Size = 0; + for (uint64_t Index = 0; Index < Code.size(); Index += Size) { + MCInst Inst; + if (!DisAsm.getInstruction(Inst, Size, + Code.slice(Index), Index, + DebugOut, CommentStream)) { + errs() << ToolName << ": warning: invalid instruction encoding\n"; + if (Size == 0) Size = 4; // skip illegible dwords + continue; + } + + PIP.printInst(IP, &Inst, Code.slice(Index, Size), + Index, outs(), "", STI); + outs() << CommentStream.str(); + Comments.clear(); + outs() << "\n"; + } + outs() << "\n"; + } +} + + static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { const Target *TheTarget = getTarget(Obj); @@ -879,6 +1008,11 @@ IP->setPrintImmHex(PrintImmHex); PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName)); + if (Obj->getArch() == Triple::amdgcn) { + DisassembleHSACodeObject(Obj, *IP, *DisAsm, *STI); + return; + } + StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " : "\t\t\t%08" PRIx64 ": ";