llvmpipe: improvements to JIT assembly dump
Fix disassembly off-by-one instruction bug, add Aarch64 support, add addresses to symbol names, cleanup iostream usage. Reviewed-by: Konstantin Seurer <konstantin.seurer@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30626>
This commit is contained in:
@@ -104,7 +104,7 @@ def lookupMap(filename, matchSymbol):
|
|||||||
|
|
||||||
def lookupAsm(filename, desiredFunction):
|
def lookupAsm(filename, desiredFunction):
|
||||||
stream = open(filename + '.asm', 'rt')
|
stream = open(filename + '.asm', 'rt')
|
||||||
while stream.readline() != desiredFunction + ':\n':
|
while not stream.readline().startswith(desiredFunction + ' '):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
asm = []
|
asm = []
|
||||||
|
@@ -126,15 +126,22 @@ disassemble(const void* func, std::ostream &buffer)
|
|||||||
* so that between runs.
|
* so that between runs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
buffer << std::setw(6) << (unsigned long)pc << ":\t";
|
buffer << std::setw(6) << std::hex << (unsigned long)pc
|
||||||
|
<< std::setw(0) << std::dec << ":";
|
||||||
|
|
||||||
Size = LLVMDisasmInstruction(D, (uint8_t *)bytes + pc, extent - pc, 0, outline,
|
Size = LLVMDisasmInstruction(D, (uint8_t *)bytes + pc, extent - pc, 0, outline,
|
||||||
sizeof outline);
|
sizeof(outline));
|
||||||
|
|
||||||
if (!Size) {
|
if (!Size) {
|
||||||
buffer << "invalid\n";
|
#if DETECT_ARCH_AARCH64
|
||||||
pc += 1;
|
uint32_t invalid = bytes[pc + 0] << 0 | bytes[pc + 1] << 8 |
|
||||||
|
bytes[pc + 2] << 16 | bytes[pc + 3] << 24;
|
||||||
|
snprintf(outline, sizeof(outline), "\tinvalid %x", invalid);
|
||||||
|
Size = 4;
|
||||||
|
#else
|
||||||
|
buffer << "\tinvalid\n";
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -145,10 +152,11 @@ disassemble(const void* func, std::ostream &buffer)
|
|||||||
unsigned i;
|
unsigned i;
|
||||||
for (i = 0; i < Size; ++i) {
|
for (i = 0; i < Size; ++i) {
|
||||||
buffer << std::hex << std::setfill('0') << std::setw(2)
|
buffer << std::hex << std::setfill('0') << std::setw(2)
|
||||||
<< static_cast<int> (bytes[pc + i]);
|
<< static_cast<int> (bytes[pc + i])
|
||||||
|
<< std::setw(0) << std::dec;
|
||||||
}
|
}
|
||||||
for (; i < 16; ++i) {
|
for (; i < 16; ++i) {
|
||||||
buffer << std::dec << " ";
|
buffer << " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,20 +164,7 @@ disassemble(const void* func, std::ostream &buffer)
|
|||||||
* Print the instruction.
|
* Print the instruction.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
buffer << std::setw(Size) << outline << '\n';
|
buffer << outline << '\n';
|
||||||
|
|
||||||
/*
|
|
||||||
* Stop disassembling on return statements, if there is no record of a
|
|
||||||
* jump to a successive address.
|
|
||||||
*
|
|
||||||
* XXX: This currently assumes x86
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if DETECT_ARCH_X86 || DETECT_ARCH_X86_64
|
|
||||||
if (Size == 1 && bytes[pc] == 0xc3) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Advance.
|
* Advance.
|
||||||
@@ -177,6 +172,21 @@ disassemble(const void* func, std::ostream &buffer)
|
|||||||
|
|
||||||
pc += Size;
|
pc += Size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop disassembling on return statements
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if DETECT_ARCH_X86 || DETECT_ARCH_X86_64
|
||||||
|
if (Size == 1 && bytes[pc - 1] == 0xc3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#elif DETECT_ARCH_AARCH64
|
||||||
|
if (Size == 4 && bytes[pc - 1] == 0xD6 && bytes[pc - 2] == 0x5F &&
|
||||||
|
(bytes[pc - 3] & 0xFC) == 0 && (bytes[pc - 4] & 0x1F) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (pc >= extent) {
|
if (pc >= extent) {
|
||||||
buffer << "disassembly larger than " << extent << " bytes, aborting\n";
|
buffer << "disassembly larger than " << extent << " bytes, aborting\n";
|
||||||
break;
|
break;
|
||||||
@@ -191,8 +201,8 @@ disassemble(const void* func, std::ostream &buffer)
|
|||||||
* Print GDB command, useful to verify output.
|
* Print GDB command, useful to verify output.
|
||||||
*/
|
*/
|
||||||
if (0) {
|
if (0) {
|
||||||
buffer << "disassemble " << static_cast<const void*>(bytes) << ' '
|
buffer << "disassemble " << std::hex << static_cast<const void*>(bytes) << ' '
|
||||||
<< static_cast<const void*>(bytes + pc) << '\n';
|
<< static_cast<const void*>(bytes + pc) << std::dec << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
return pc;
|
return pc;
|
||||||
@@ -248,7 +258,8 @@ lp_profile(LLVMValueRef func, const void *code)
|
|||||||
if (perf_map_file) {
|
if (perf_map_file) {
|
||||||
const char *symbol = LLVMGetValueName(func);
|
const char *symbol = LLVMGetValueName(func);
|
||||||
unsigned long addr = (uintptr_t)code;
|
unsigned long addr = (uintptr_t)code;
|
||||||
perf_asm_file << symbol << ":\n";
|
perf_asm_file << symbol << " " << std::hex
|
||||||
|
<< (uintptr_t)code << std::dec << ":\n";
|
||||||
unsigned long size = disassemble(code, perf_asm_file);
|
unsigned long size = disassemble(code, perf_asm_file);
|
||||||
perf_asm_file.flush();
|
perf_asm_file.flush();
|
||||||
fprintf(perf_map_file, "%lx %lx %s\n", addr, size, symbol);
|
fprintf(perf_map_file, "%lx %lx %s\n", addr, size, symbol);
|
||||||
@@ -259,5 +270,3 @@ lp_profile(LLVMValueRef func, const void *code)
|
|||||||
(void)code;
|
(void)code;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user