From beec259520cdd519207c12d0399d31dcac1a0ad8 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Mon, 11 May 2026 01:30:28 +0200 Subject: [PATCH] Extract symbol code disassembly into a separate source file. Two bugs fixed in the process: 1. X86_REG_BPL is now properly set (previously there were duplicate X86_REG_BP entries). 2. maxLine is now properly calculated, instead of being set to the last line value. --- profiler/CMakeLists.txt | 1 + profiler/src/profiler/TracyDisassembly.cpp | 592 ++++++++++++++++++++ profiler/src/profiler/TracyDisassembly.hpp | 113 ++++ profiler/src/profiler/TracySourceView.cpp | 597 +-------------------- profiler/src/profiler/TracySourceView.hpp | 81 +-- 5 files changed, 732 insertions(+), 652 deletions(-) create mode 100644 profiler/src/profiler/TracyDisassembly.cpp create mode 100644 profiler/src/profiler/TracyDisassembly.hpp diff --git a/profiler/CMakeLists.txt b/profiler/CMakeLists.txt index 3cef85f9..aa8fd5ee 100644 --- a/profiler/CMakeLists.txt +++ b/profiler/CMakeLists.txt @@ -59,6 +59,7 @@ set(SERVER_FILES TracyBadVersion.cpp TracyColor.cpp TracyConfig.cpp + TracyDisassembly.cpp TracyEmbed.cpp TracyEventDebug.cpp TracyFileselector.cpp diff --git a/profiler/src/profiler/TracyDisassembly.cpp b/profiler/src/profiler/TracyDisassembly.cpp new file mode 100644 index 00000000..ec398497 --- /dev/null +++ b/profiler/src/profiler/TracyDisassembly.cpp @@ -0,0 +1,592 @@ +#include +#include + +#include "TracyDisassembly.hpp" +#include "tracy_pdqsort.h" +#include "../server/TracyWorker.hpp" + +namespace tracy +{ + +static RegsX86 s_regMapX86[X86_REG_ENDING]; + +struct InitRegMapX86 +{ + InitRegMapX86() + { + memset( s_regMapX86, 0, sizeof( s_regMapX86 ) ); + + s_regMapX86[X86_REG_EFLAGS] = RegsX86::flags; + s_regMapX86[X86_REG_AH] = RegsX86::rax; + s_regMapX86[X86_REG_AL] = RegsX86::rax; + s_regMapX86[X86_REG_AX] = RegsX86::rax; + s_regMapX86[X86_REG_EAX] = RegsX86::rax; + s_regMapX86[X86_REG_RAX] = RegsX86::rax; + s_regMapX86[X86_REG_BH] = RegsX86::rbx; + s_regMapX86[X86_REG_BL] = RegsX86::rbx; + s_regMapX86[X86_REG_BX] = RegsX86::rbx; + s_regMapX86[X86_REG_EBX] = RegsX86::rbx; + s_regMapX86[X86_REG_RBX] = RegsX86::rbx; + s_regMapX86[X86_REG_CH] = RegsX86::rcx; + s_regMapX86[X86_REG_CL] = RegsX86::rcx; + s_regMapX86[X86_REG_CX] = RegsX86::rcx; + s_regMapX86[X86_REG_ECX] = RegsX86::rcx; + s_regMapX86[X86_REG_RCX] = RegsX86::rcx; + s_regMapX86[X86_REG_DH] = RegsX86::rdx; + s_regMapX86[X86_REG_DL] = RegsX86::rdx; + s_regMapX86[X86_REG_DX] = RegsX86::rdx; + s_regMapX86[X86_REG_EDX] = RegsX86::rdx; + s_regMapX86[X86_REG_RDX] = RegsX86::rdx; + s_regMapX86[X86_REG_SIL] = RegsX86::rsi; + s_regMapX86[X86_REG_SI] = RegsX86::rsi; + s_regMapX86[X86_REG_ESI] = RegsX86::rsi; + s_regMapX86[X86_REG_RSI] = RegsX86::rsi; + s_regMapX86[X86_REG_DIL] = RegsX86::rdi; + s_regMapX86[X86_REG_DI] = RegsX86::rdi; + s_regMapX86[X86_REG_EDI] = RegsX86::rdi; + s_regMapX86[X86_REG_RDI] = RegsX86::rdi; + s_regMapX86[X86_REG_BPL] = RegsX86::rbp; + s_regMapX86[X86_REG_BP] = RegsX86::rbp; + s_regMapX86[X86_REG_EBP] = RegsX86::rbp; + s_regMapX86[X86_REG_RBP] = RegsX86::rbp; + s_regMapX86[X86_REG_SPL] = RegsX86::rsp; + s_regMapX86[X86_REG_SP] = RegsX86::rsp; + s_regMapX86[X86_REG_ESP] = RegsX86::rsp; + s_regMapX86[X86_REG_RSP] = RegsX86::rsp; + s_regMapX86[X86_REG_R8B] = RegsX86::r8; + s_regMapX86[X86_REG_R8W] = RegsX86::r8; + s_regMapX86[X86_REG_R8D] = RegsX86::r8; + s_regMapX86[X86_REG_R8] = RegsX86::r8; + s_regMapX86[X86_REG_R9B] = RegsX86::r9; + s_regMapX86[X86_REG_R9W] = RegsX86::r9; + s_regMapX86[X86_REG_R9D] = RegsX86::r9; + s_regMapX86[X86_REG_R9] = RegsX86::r9; + s_regMapX86[X86_REG_R10B] = RegsX86::r10; + s_regMapX86[X86_REG_R10W] = RegsX86::r10; + s_regMapX86[X86_REG_R10D] = RegsX86::r10; + s_regMapX86[X86_REG_R10] = RegsX86::r10; + s_regMapX86[X86_REG_R11B] = RegsX86::r11; + s_regMapX86[X86_REG_R11W] = RegsX86::r11; + s_regMapX86[X86_REG_R11D] = RegsX86::r11; + s_regMapX86[X86_REG_R11] = RegsX86::r11; + s_regMapX86[X86_REG_R12B] = RegsX86::r12; + s_regMapX86[X86_REG_R12W] = RegsX86::r12; + s_regMapX86[X86_REG_R12D] = RegsX86::r12; + s_regMapX86[X86_REG_R12] = RegsX86::r12; + s_regMapX86[X86_REG_R13B] = RegsX86::r13; + s_regMapX86[X86_REG_R13W] = RegsX86::r13; + s_regMapX86[X86_REG_R13D] = RegsX86::r13; + s_regMapX86[X86_REG_R13] = RegsX86::r13; + s_regMapX86[X86_REG_R14B] = RegsX86::r14; + s_regMapX86[X86_REG_R14W] = RegsX86::r14; + s_regMapX86[X86_REG_R14D] = RegsX86::r14; + s_regMapX86[X86_REG_R14] = RegsX86::r14; + s_regMapX86[X86_REG_R15B] = RegsX86::r15; + s_regMapX86[X86_REG_R15W] = RegsX86::r15; + s_regMapX86[X86_REG_R15D] = RegsX86::r15; + s_regMapX86[X86_REG_R15] = RegsX86::r15; + s_regMapX86[X86_REG_MM0] = RegsX86::mm0; + s_regMapX86[X86_REG_MM1] = RegsX86::mm1; + s_regMapX86[X86_REG_MM2] = RegsX86::mm2; + s_regMapX86[X86_REG_MM3] = RegsX86::mm3; + s_regMapX86[X86_REG_MM4] = RegsX86::mm4; + s_regMapX86[X86_REG_MM5] = RegsX86::mm5; + s_regMapX86[X86_REG_MM6] = RegsX86::mm6; + s_regMapX86[X86_REG_MM7] = RegsX86::mm7; + s_regMapX86[X86_REG_ST0] = RegsX86::mm0; + s_regMapX86[X86_REG_ST1] = RegsX86::mm1; + s_regMapX86[X86_REG_ST2] = RegsX86::mm2; + s_regMapX86[X86_REG_ST3] = RegsX86::mm3; + s_regMapX86[X86_REG_ST4] = RegsX86::mm4; + s_regMapX86[X86_REG_ST5] = RegsX86::mm5; + s_regMapX86[X86_REG_ST6] = RegsX86::mm6; + s_regMapX86[X86_REG_ST7] = RegsX86::mm7; + s_regMapX86[X86_REG_XMM0] = RegsX86::xmm0; + s_regMapX86[X86_REG_YMM0] = RegsX86::xmm0; + s_regMapX86[X86_REG_ZMM0] = RegsX86::xmm0; + s_regMapX86[X86_REG_XMM1] = RegsX86::xmm1; + s_regMapX86[X86_REG_YMM1] = RegsX86::xmm1; + s_regMapX86[X86_REG_ZMM1] = RegsX86::xmm1; + s_regMapX86[X86_REG_XMM2] = RegsX86::xmm2; + s_regMapX86[X86_REG_YMM2] = RegsX86::xmm2; + s_regMapX86[X86_REG_ZMM2] = RegsX86::xmm2; + s_regMapX86[X86_REG_XMM3] = RegsX86::xmm3; + s_regMapX86[X86_REG_YMM3] = RegsX86::xmm3; + s_regMapX86[X86_REG_ZMM3] = RegsX86::xmm3; + s_regMapX86[X86_REG_XMM4] = RegsX86::xmm4; + s_regMapX86[X86_REG_YMM4] = RegsX86::xmm4; + s_regMapX86[X86_REG_ZMM4] = RegsX86::xmm4; + s_regMapX86[X86_REG_XMM5] = RegsX86::xmm5; + s_regMapX86[X86_REG_YMM5] = RegsX86::xmm5; + s_regMapX86[X86_REG_ZMM5] = RegsX86::xmm5; + s_regMapX86[X86_REG_XMM6] = RegsX86::xmm6; + s_regMapX86[X86_REG_YMM6] = RegsX86::xmm6; + s_regMapX86[X86_REG_ZMM6] = RegsX86::xmm6; + s_regMapX86[X86_REG_XMM7] = RegsX86::xmm7; + s_regMapX86[X86_REG_YMM7] = RegsX86::xmm7; + s_regMapX86[X86_REG_ZMM7] = RegsX86::xmm7; + s_regMapX86[X86_REG_XMM8] = RegsX86::xmm8; + s_regMapX86[X86_REG_YMM8] = RegsX86::xmm8; + s_regMapX86[X86_REG_ZMM8] = RegsX86::xmm8; + s_regMapX86[X86_REG_XMM9] = RegsX86::xmm9; + s_regMapX86[X86_REG_YMM9] = RegsX86::xmm9; + s_regMapX86[X86_REG_ZMM9] = RegsX86::xmm9; + s_regMapX86[X86_REG_XMM10] = RegsX86::xmm10; + s_regMapX86[X86_REG_YMM10] = RegsX86::xmm10; + s_regMapX86[X86_REG_ZMM10] = RegsX86::xmm10; + s_regMapX86[X86_REG_XMM11] = RegsX86::xmm11; + s_regMapX86[X86_REG_YMM11] = RegsX86::xmm11; + s_regMapX86[X86_REG_ZMM11] = RegsX86::xmm11; + s_regMapX86[X86_REG_XMM12] = RegsX86::xmm12; + s_regMapX86[X86_REG_YMM12] = RegsX86::xmm12; + s_regMapX86[X86_REG_ZMM12] = RegsX86::xmm12; + s_regMapX86[X86_REG_XMM13] = RegsX86::xmm13; + s_regMapX86[X86_REG_YMM13] = RegsX86::xmm13; + s_regMapX86[X86_REG_ZMM13] = RegsX86::xmm13; + s_regMapX86[X86_REG_XMM14] = RegsX86::xmm14; + s_regMapX86[X86_REG_YMM14] = RegsX86::xmm14; + s_regMapX86[X86_REG_ZMM14] = RegsX86::xmm14; + s_regMapX86[X86_REG_XMM15] = RegsX86::xmm15; + s_regMapX86[X86_REG_YMM15] = RegsX86::xmm15; + s_regMapX86[X86_REG_ZMM15] = RegsX86::xmm15; + s_regMapX86[X86_REG_XMM16] = RegsX86::xmm16; + s_regMapX86[X86_REG_YMM16] = RegsX86::xmm16; + s_regMapX86[X86_REG_ZMM16] = RegsX86::xmm16; + s_regMapX86[X86_REG_XMM17] = RegsX86::xmm17; + s_regMapX86[X86_REG_YMM17] = RegsX86::xmm17; + s_regMapX86[X86_REG_ZMM17] = RegsX86::xmm17; + s_regMapX86[X86_REG_XMM18] = RegsX86::xmm18; + s_regMapX86[X86_REG_YMM18] = RegsX86::xmm18; + s_regMapX86[X86_REG_ZMM18] = RegsX86::xmm18; + s_regMapX86[X86_REG_XMM19] = RegsX86::xmm19; + s_regMapX86[X86_REG_YMM19] = RegsX86::xmm19; + s_regMapX86[X86_REG_ZMM19] = RegsX86::xmm19; + s_regMapX86[X86_REG_XMM20] = RegsX86::xmm20; + s_regMapX86[X86_REG_YMM20] = RegsX86::xmm20; + s_regMapX86[X86_REG_ZMM20] = RegsX86::xmm20; + s_regMapX86[X86_REG_XMM21] = RegsX86::xmm21; + s_regMapX86[X86_REG_YMM21] = RegsX86::xmm21; + s_regMapX86[X86_REG_ZMM21] = RegsX86::xmm21; + s_regMapX86[X86_REG_XMM22] = RegsX86::xmm22; + s_regMapX86[X86_REG_YMM22] = RegsX86::xmm22; + s_regMapX86[X86_REG_ZMM22] = RegsX86::xmm22; + s_regMapX86[X86_REG_XMM23] = RegsX86::xmm23; + s_regMapX86[X86_REG_YMM23] = RegsX86::xmm23; + s_regMapX86[X86_REG_ZMM23] = RegsX86::xmm23; + s_regMapX86[X86_REG_XMM24] = RegsX86::xmm24; + s_regMapX86[X86_REG_YMM24] = RegsX86::xmm24; + s_regMapX86[X86_REG_ZMM24] = RegsX86::xmm24; + s_regMapX86[X86_REG_XMM25] = RegsX86::xmm25; + s_regMapX86[X86_REG_YMM25] = RegsX86::xmm25; + s_regMapX86[X86_REG_ZMM25] = RegsX86::xmm25; + s_regMapX86[X86_REG_XMM26] = RegsX86::xmm26; + s_regMapX86[X86_REG_YMM26] = RegsX86::xmm26; + s_regMapX86[X86_REG_ZMM26] = RegsX86::xmm26; + s_regMapX86[X86_REG_XMM27] = RegsX86::xmm27; + s_regMapX86[X86_REG_YMM27] = RegsX86::xmm27; + s_regMapX86[X86_REG_ZMM27] = RegsX86::xmm27; + s_regMapX86[X86_REG_XMM28] = RegsX86::xmm28; + s_regMapX86[X86_REG_YMM28] = RegsX86::xmm28; + s_regMapX86[X86_REG_ZMM28] = RegsX86::xmm28; + s_regMapX86[X86_REG_XMM29] = RegsX86::xmm29; + s_regMapX86[X86_REG_YMM29] = RegsX86::xmm29; + s_regMapX86[X86_REG_ZMM29] = RegsX86::xmm29; + s_regMapX86[X86_REG_XMM30] = RegsX86::xmm30; + s_regMapX86[X86_REG_YMM30] = RegsX86::xmm30; + s_regMapX86[X86_REG_ZMM30] = RegsX86::xmm30; + s_regMapX86[X86_REG_XMM31] = RegsX86::xmm31; + s_regMapX86[X86_REG_YMM31] = RegsX86::xmm31; + s_regMapX86[X86_REG_ZMM31] = RegsX86::xmm31; + s_regMapX86[X86_REG_K0] = RegsX86::k0; + s_regMapX86[X86_REG_K1] = RegsX86::k1; + s_regMapX86[X86_REG_K2] = RegsX86::k2; + s_regMapX86[X86_REG_K3] = RegsX86::k3; + s_regMapX86[X86_REG_K4] = RegsX86::k4; + s_regMapX86[X86_REG_K5] = RegsX86::k5; + s_regMapX86[X86_REG_K6] = RegsX86::k6; + s_regMapX86[X86_REG_K7] = RegsX86::k7; + } +}; + +static bool IsJumpConditionalX86( const char* op ) +{ + static constexpr const char* branchX86[] = { + "je", "jne", "jg", "jge", "ja", "jae", "jl", "jle", "jb", "jbe", "jo", "jno", "jz", "jnz", "js", "jns", "jcxz", "jecxz", "jrcxz", "loop", "loope", + "loopne", "loopnz", "loopz", "jnle", "jnl", "jnge", "jng", "jnbe", "jnb", "jnae", "jna", "jc", "jnc", "jp", "jpe", "jnp", "jpo", nullptr + }; + auto ptr = branchX86; + while( *ptr ) if( strcmp( *ptr++, op ) == 0 ) return true; + return false; +} + +DisasmData Disassemble( uint64_t symAddr, const Worker& worker ) +{ + DisasmData data = {}; + data.disasmFail = -1; + + if( symAddr == 0 ) return data; + data.cpuArch = worker.GetCpuArch(); + if( data.cpuArch == CpuArchUnknown ) return data; + uint32_t len; + auto code = worker.GetSymbolCode( symAddr, len ); + if( !code ) return data; + data.codeLen = len; + + static InitRegMapX86 regMapInit; + + csh handle; + cs_err rval = CS_ERR_ARCH; + switch( data.cpuArch ) + { + case CpuArchX86: + rval = cs_open( CS_ARCH_X86, CS_MODE_32, &handle ); + break; + case CpuArchX64: + rval = cs_open( CS_ARCH_X86, CS_MODE_64, &handle ); + break; + case CpuArchArm32: + rval = cs_open( CS_ARCH_ARM, CS_MODE_ARM, &handle ); + break; + case CpuArchArm64: + rval = cs_open( CS_ARCH_AARCH64, CS_MODE_ARM, &handle ); + break; + default: + assert( false ); + break; + } + if( rval != CS_ERR_OK ) return data; + + Tokenizer tokenizer; + + cs_option( handle, CS_OPT_DETAIL, CS_OPT_ON ); + cs_option( handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL ); + cs_insn* insn; + size_t cnt = cs_disasm( handle, (const uint8_t*)code, len, symAddr, 0, &insn ); + if( cnt > 0 ) + { + if( insn[cnt-1].address - symAddr + insn[cnt-1].size < len ) data.disasmFail = insn[cnt-1].address - symAddr; + int bytesMax = 0; + int mLenMax = 0; + int oLenMax = 0; + data.lines.reserve( cnt ); + for( size_t i=0; i= symAddr && jumpAddr < symAddr + len ) + { + auto fit = std::lower_bound( insn, insn+cnt, jumpAddr, []( const auto& l, const auto& r ) { return l.address < r; } ); + if( fit != insn+cnt && fit->address == jumpAddr ) + { + const auto min = std::min( jumpAddr, op.address ); + const auto max = std::max( jumpAddr, op.address ); + auto it = data.jumpTable.find( jumpAddr ); + if( it == data.jumpTable.end() ) + { + data.jumpTable.emplace( jumpAddr, AsmJumpData { min, max, 0, { op.address } } ); + } + else + { + if( it->second.min > min ) it->second.min = min; + else if( it->second.max < max ) it->second.max = max; + it->second.source.emplace_back( op.address ); + } + } + else + { + jumpAddr = 0; + } + } + else + { + data.jumpOut.emplace( op.address ); + } + } + std::vector params; + switch( data.cpuArch ) + { + case CpuArchX86: + case CpuArchX64: + for( uint8_t i=0; ix86.op_count == 2 ); + assert( op.detail->x86.operands[1].type == X86_OP_MEM ); + auto& mem = op.detail->x86.operands[1].mem; + if( mem.base == X86_REG_INVALID ) + { + if( mem.index == X86_REG_INVALID ) + { + leaData = AsmLeaData::d; + } + else + { + leaData = mem.disp == 0 ? AsmLeaData::i : AsmLeaData::id; + } + } + else if( mem.base == X86_REG_RIP ) + { + leaData = mem.disp == 0 ? AsmLeaData::r : AsmLeaData::rd; + } + else + { + if( mem.index == X86_REG_INVALID ) + { + leaData = mem.disp == 0 ? AsmLeaData::b : AsmLeaData::bd; + } + else + { + leaData = mem.disp == 0 ? AsmLeaData::bi : AsmLeaData::bid; + } + } + } + data.lines.emplace_back( AsmLine { op.address, jumpAddr, op.mnemonic, op.op_str, (uint8_t)op.size, leaData, opType, jumpConditional, std::move( params ) } ); + const auto& operands = data.lines.back().operands; + data.lines.back().opTokens = tokenizer.TokenizeAsm( operands.c_str(), operands.c_str() + operands.size() ); + +#if CS_API_MAJOR >= 4 + auto& entry = data.lines.back(); + cs_regs read, write; + uint8_t rcnt, wcnt; + cs_regs_access( handle, &op, read, &rcnt, write, &wcnt ); + int idx; + switch( data.cpuArch ) + { + case CpuArchX86: + case CpuArchX64: + assert( rcnt < sizeof( entry.readX86 ) ); + assert( wcnt < sizeof( entry.writeX86 ) ); + idx = 0; + for( int i=0; i mLenMax ) mLenMax = mLen; + const auto oLen = (int)strlen( op.op_str ); + if( oLen > oLenMax ) oLenMax = oLen; + if( op.size > bytesMax ) bytesMax = op.size; + + uint32_t mLineMax = 0; + uint32_t srcline; + const auto srcidx = worker.GetLocationForAddress( op.address, srcline ); + if( srcidx.Active() ) + { + mLineMax = srcline; + const auto idx = srcidx.Idx(); + auto sit = data.sourceFiles.find( idx ); + if( sit == data.sourceFiles.end() ) data.sourceFiles.emplace( idx, srcline ); + } + char tmp[16]; + sprintf( tmp, "%" PRIu32, mLineMax ); + data.maxLine = std::max( data.maxLine, strlen( tmp ) + 1 ); + } + cs_free( insn, cnt ); + data.maxMnemonicLen = mLenMax + 1; + data.maxOperandLen = oLenMax + 1; + data.maxAsmBytes = bytesMax; + if( !data.jumpTable.empty() ) + { + struct JumpRange + { + uint64_t target; + uint64_t len; + }; + std::vector jumpRange; + jumpRange.reserve( data.jumpTable.size() ); + for( auto& v : data.jumpTable ) + { + pdqsort_branchless( v.second.source.begin(), v.second.source.end() ); + jumpRange.emplace_back( JumpRange { v.first, v.second.max - v.second.min } ); + } + pdqsort_branchless( jumpRange.begin(), jumpRange.end(), []( const auto& l, const auto& r ) { return l.len < r.len; } ); + std::vector>> levelRanges; + for( auto& v : jumpRange ) + { + auto it = data.jumpTable.find( v.target ); + assert( it != data.jumpTable.end() ); + size_t level = 0; + for(;;) + { + assert( levelRanges.size() >= level ); + if( levelRanges.size() == level ) + { + it->second.level = level; + levelRanges.push_back( { { it->second.min, it->second.max } } ); + break; + } + else + { + bool validFit = true; + auto& lr = levelRanges[level]; + for( auto& range : lr ) + { + assert( !( it->second.min >= range.first && it->second.max <= range.second ) ); + if( it->second.min <= range.second && it->second.max >= range.first ) + { + validFit = false; + break; + } + } + if( validFit ) + { + it->second.level = level; + lr.emplace_back( it->second.min, it->second.max ); + break; + } + level++; + } + } + if( level > data.maxJumpLevel ) data.maxJumpLevel = level; + } + + uint32_t locNum = 0; + for( auto& v : data.lines ) + { + if( data.jumpTable.contains( v.addr ) ) + { + data.locMap.emplace( v.addr, locNum++ ); + } + } + } + } + cs_close( &handle ); + + return data; +} + +} diff --git a/profiler/src/profiler/TracyDisassembly.hpp b/profiler/src/profiler/TracyDisassembly.hpp new file mode 100644 index 00000000..93bb2e66 --- /dev/null +++ b/profiler/src/profiler/TracyDisassembly.hpp @@ -0,0 +1,113 @@ +#ifndef __TRACYDISASSEMBLY_HPP__ +#define __TRACYDISASSEMBLY_HPP__ + +#include +#include +#include + +#include "tracy_robin_hood.h" +#include "TracyProtocol.hpp" +#include "TracySourceTokenizer.hpp" + +namespace tracy +{ + +class Worker; + +enum class RegsX86 : uint8_t +{ + invalid, flags, + rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, r8, r9, r10, r11, r12, r13, r14, r15, + mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, + xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, xmm16, xmm17, xmm18, xmm19, + xmm20, xmm21, xmm22, xmm23, xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, + xmm30, xmm31, k0, k1, k2, k3, k4, k5, k6, k7, + NUMBER_OF_ENTRIES +}; + +enum class AsmLeaData : uint8_t +{ + none, + b, + bd, + bi, + bid, + d, + i, + id, + r, + rd +}; + +enum class AsmOpType : uint8_t +{ + None, + Jump, + Branch, + Call, + Ret, + Privileged +}; + +struct AsmOpParams +{ + uint8_t type; + uint16_t width; +}; + +struct AsmJumpData +{ + uint64_t min; + uint64_t max; + size_t level; + std::vector source; +}; + +struct AsmLine +{ + uint64_t addr; + uint64_t jumpAddr; + std::string mnemonic; + std::string operands; + uint8_t len; + AsmLeaData leaData; + AsmOpType opType; + bool jumpConditional; + std::vector params; + std::vector opTokens; + union + { + RegsX86 readX86[12]; + }; + union + { + RegsX86 writeX86[20]; + }; + uint16_t regData[20]; +}; + +struct DisasmData +{ + std::vector lines; + unordered_flat_map locMap; + unordered_flat_map jumpTable; + unordered_flat_set jumpOut; + unordered_flat_map sourceFiles; + + size_t maxJumpLevel; + int32_t disasmFail; + uint32_t codeLen; + size_t maxLine; + int maxMnemonicLen; + int maxOperandLen; + uint8_t maxAsmBytes; + + CpuArchitecture cpuArch; +}; + +DisasmData Disassemble( uint64_t symAddr, const Worker& worker ); + +} + +#endif diff --git a/profiler/src/profiler/TracySourceView.cpp b/profiler/src/profiler/TracySourceView.cpp index c54ef7eb..78718a59 100644 --- a/profiler/src/profiler/TracySourceView.cpp +++ b/profiler/src/profiler/TracySourceView.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include "imgui.h" #include "TracyCharUtil.hpp" #include "TracyColor.hpp" @@ -80,9 +78,7 @@ static constexpr const char* s_regNameX86[] = { "xmm20", "xmm21", "xmm22", "xmm23", "xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" }; -static_assert( sizeof( s_regNameX86 ) / sizeof( *s_regNameX86 ) == (size_t)SourceView::RegsX86::NUMBER_OF_ENTRIES, "Invalid x86 register name table" ); - -static SourceView::RegsX86 s_regMapX86[X86_REG_ENDING]; +static_assert( sizeof( s_regNameX86 ) / sizeof( *s_regNameX86 ) == (size_t)RegsX86::NUMBER_OF_ENTRIES, "Invalid x86 register name table" ); static constexpr const char* s_CostName[] = { @@ -280,198 +276,6 @@ SourceView::SourceView() { m_microArchOpMap.emplace( OpsList[i], i ); } - - memset( s_regMapX86, 0, sizeof( s_regMapX86 ) ); - - s_regMapX86[X86_REG_EFLAGS] = RegsX86::flags; - s_regMapX86[X86_REG_AH] = RegsX86::rax; - s_regMapX86[X86_REG_AL] = RegsX86::rax; - s_regMapX86[X86_REG_AX] = RegsX86::rax; - s_regMapX86[X86_REG_EAX] = RegsX86::rax; - s_regMapX86[X86_REG_RAX] = RegsX86::rax; - s_regMapX86[X86_REG_BH] = RegsX86::rbx; - s_regMapX86[X86_REG_BL] = RegsX86::rbx; - s_regMapX86[X86_REG_BX] = RegsX86::rbx; - s_regMapX86[X86_REG_EBX] = RegsX86::rbx; - s_regMapX86[X86_REG_RBX] = RegsX86::rbx; - s_regMapX86[X86_REG_CH] = RegsX86::rcx; - s_regMapX86[X86_REG_CL] = RegsX86::rcx; - s_regMapX86[X86_REG_CX] = RegsX86::rcx; - s_regMapX86[X86_REG_ECX] = RegsX86::rcx; - s_regMapX86[X86_REG_RCX] = RegsX86::rcx; - s_regMapX86[X86_REG_DH] = RegsX86::rdx; - s_regMapX86[X86_REG_DL] = RegsX86::rdx; - s_regMapX86[X86_REG_DX] = RegsX86::rdx; - s_regMapX86[X86_REG_EDX] = RegsX86::rdx; - s_regMapX86[X86_REG_RDX] = RegsX86::rdx; - s_regMapX86[X86_REG_SIL] = RegsX86::rsi; - s_regMapX86[X86_REG_SI] = RegsX86::rsi; - s_regMapX86[X86_REG_ESI] = RegsX86::rsi; - s_regMapX86[X86_REG_RSI] = RegsX86::rsi; - s_regMapX86[X86_REG_DIL] = RegsX86::rdi; - s_regMapX86[X86_REG_DI] = RegsX86::rdi; - s_regMapX86[X86_REG_EDI] = RegsX86::rdi; - s_regMapX86[X86_REG_RDI] = RegsX86::rdi; - s_regMapX86[X86_REG_BP] = RegsX86::rbp; - s_regMapX86[X86_REG_BP] = RegsX86::rbp; - s_regMapX86[X86_REG_EBP] = RegsX86::rbp; - s_regMapX86[X86_REG_RBP] = RegsX86::rbp; - s_regMapX86[X86_REG_SPL] = RegsX86::rsp; - s_regMapX86[X86_REG_SP] = RegsX86::rsp; - s_regMapX86[X86_REG_ESP] = RegsX86::rsp; - s_regMapX86[X86_REG_RSP] = RegsX86::rsp; - s_regMapX86[X86_REG_R8B] = RegsX86::r8; - s_regMapX86[X86_REG_R8W] = RegsX86::r8; - s_regMapX86[X86_REG_R8D] = RegsX86::r8; - s_regMapX86[X86_REG_R8] = RegsX86::r8; - s_regMapX86[X86_REG_R9B] = RegsX86::r9; - s_regMapX86[X86_REG_R9W] = RegsX86::r9; - s_regMapX86[X86_REG_R9D] = RegsX86::r9; - s_regMapX86[X86_REG_R9] = RegsX86::r9; - s_regMapX86[X86_REG_R10B] = RegsX86::r10; - s_regMapX86[X86_REG_R10W] = RegsX86::r10; - s_regMapX86[X86_REG_R10D] = RegsX86::r10; - s_regMapX86[X86_REG_R10] = RegsX86::r10; - s_regMapX86[X86_REG_R11B] = RegsX86::r11; - s_regMapX86[X86_REG_R11W] = RegsX86::r11; - s_regMapX86[X86_REG_R11D] = RegsX86::r11; - s_regMapX86[X86_REG_R11] = RegsX86::r11; - s_regMapX86[X86_REG_R12B] = RegsX86::r12; - s_regMapX86[X86_REG_R12W] = RegsX86::r12; - s_regMapX86[X86_REG_R12D] = RegsX86::r12; - s_regMapX86[X86_REG_R12] = RegsX86::r12; - s_regMapX86[X86_REG_R13B] = RegsX86::r13; - s_regMapX86[X86_REG_R13W] = RegsX86::r13; - s_regMapX86[X86_REG_R13D] = RegsX86::r13; - s_regMapX86[X86_REG_R13] = RegsX86::r13; - s_regMapX86[X86_REG_R14B] = RegsX86::r14; - s_regMapX86[X86_REG_R14W] = RegsX86::r14; - s_regMapX86[X86_REG_R14D] = RegsX86::r14; - s_regMapX86[X86_REG_R14] = RegsX86::r14; - s_regMapX86[X86_REG_R15B] = RegsX86::r15; - s_regMapX86[X86_REG_R15W] = RegsX86::r15; - s_regMapX86[X86_REG_R15D] = RegsX86::r15; - s_regMapX86[X86_REG_R15] = RegsX86::r15; - s_regMapX86[X86_REG_MM0] = RegsX86::mm0; - s_regMapX86[X86_REG_MM1] = RegsX86::mm1; - s_regMapX86[X86_REG_MM2] = RegsX86::mm2; - s_regMapX86[X86_REG_MM3] = RegsX86::mm3; - s_regMapX86[X86_REG_MM4] = RegsX86::mm4; - s_regMapX86[X86_REG_MM5] = RegsX86::mm5; - s_regMapX86[X86_REG_MM6] = RegsX86::mm6; - s_regMapX86[X86_REG_MM7] = RegsX86::mm7; - s_regMapX86[X86_REG_ST0] = RegsX86::mm0; - s_regMapX86[X86_REG_ST1] = RegsX86::mm1; - s_regMapX86[X86_REG_ST2] = RegsX86::mm2; - s_regMapX86[X86_REG_ST3] = RegsX86::mm3; - s_regMapX86[X86_REG_ST4] = RegsX86::mm4; - s_regMapX86[X86_REG_ST5] = RegsX86::mm5; - s_regMapX86[X86_REG_ST6] = RegsX86::mm6; - s_regMapX86[X86_REG_ST7] = RegsX86::mm7; - s_regMapX86[X86_REG_XMM0] = RegsX86::xmm0; - s_regMapX86[X86_REG_YMM0] = RegsX86::xmm0; - s_regMapX86[X86_REG_ZMM0] = RegsX86::xmm0; - s_regMapX86[X86_REG_XMM1] = RegsX86::xmm1; - s_regMapX86[X86_REG_YMM1] = RegsX86::xmm1; - s_regMapX86[X86_REG_ZMM1] = RegsX86::xmm1; - s_regMapX86[X86_REG_XMM2] = RegsX86::xmm2; - s_regMapX86[X86_REG_YMM2] = RegsX86::xmm2; - s_regMapX86[X86_REG_ZMM2] = RegsX86::xmm2; - s_regMapX86[X86_REG_XMM3] = RegsX86::xmm3; - s_regMapX86[X86_REG_YMM3] = RegsX86::xmm3; - s_regMapX86[X86_REG_ZMM3] = RegsX86::xmm3; - s_regMapX86[X86_REG_XMM4] = RegsX86::xmm4; - s_regMapX86[X86_REG_YMM4] = RegsX86::xmm4; - s_regMapX86[X86_REG_ZMM4] = RegsX86::xmm4; - s_regMapX86[X86_REG_XMM5] = RegsX86::xmm5; - s_regMapX86[X86_REG_YMM5] = RegsX86::xmm5; - s_regMapX86[X86_REG_ZMM5] = RegsX86::xmm5; - s_regMapX86[X86_REG_XMM6] = RegsX86::xmm6; - s_regMapX86[X86_REG_YMM6] = RegsX86::xmm6; - s_regMapX86[X86_REG_ZMM6] = RegsX86::xmm6; - s_regMapX86[X86_REG_XMM7] = RegsX86::xmm7; - s_regMapX86[X86_REG_YMM7] = RegsX86::xmm7; - s_regMapX86[X86_REG_ZMM7] = RegsX86::xmm7; - s_regMapX86[X86_REG_XMM8] = RegsX86::xmm8; - s_regMapX86[X86_REG_YMM8] = RegsX86::xmm8; - s_regMapX86[X86_REG_ZMM8] = RegsX86::xmm8; - s_regMapX86[X86_REG_XMM9] = RegsX86::xmm9; - s_regMapX86[X86_REG_YMM9] = RegsX86::xmm9; - s_regMapX86[X86_REG_ZMM9] = RegsX86::xmm9; - s_regMapX86[X86_REG_XMM10] = RegsX86::xmm10; - s_regMapX86[X86_REG_YMM10] = RegsX86::xmm10; - s_regMapX86[X86_REG_ZMM10] = RegsX86::xmm10; - s_regMapX86[X86_REG_XMM11] = RegsX86::xmm11; - s_regMapX86[X86_REG_YMM11] = RegsX86::xmm11; - s_regMapX86[X86_REG_ZMM11] = RegsX86::xmm11; - s_regMapX86[X86_REG_XMM12] = RegsX86::xmm12; - s_regMapX86[X86_REG_YMM12] = RegsX86::xmm12; - s_regMapX86[X86_REG_ZMM12] = RegsX86::xmm12; - s_regMapX86[X86_REG_XMM13] = RegsX86::xmm13; - s_regMapX86[X86_REG_YMM13] = RegsX86::xmm13; - s_regMapX86[X86_REG_ZMM13] = RegsX86::xmm13; - s_regMapX86[X86_REG_XMM14] = RegsX86::xmm14; - s_regMapX86[X86_REG_YMM14] = RegsX86::xmm14; - s_regMapX86[X86_REG_ZMM14] = RegsX86::xmm14; - s_regMapX86[X86_REG_XMM15] = RegsX86::xmm15; - s_regMapX86[X86_REG_YMM15] = RegsX86::xmm15; - s_regMapX86[X86_REG_ZMM15] = RegsX86::xmm15; - s_regMapX86[X86_REG_XMM16] = RegsX86::xmm16; - s_regMapX86[X86_REG_YMM16] = RegsX86::xmm16; - s_regMapX86[X86_REG_ZMM16] = RegsX86::xmm16; - s_regMapX86[X86_REG_XMM17] = RegsX86::xmm17; - s_regMapX86[X86_REG_YMM17] = RegsX86::xmm17; - s_regMapX86[X86_REG_ZMM17] = RegsX86::xmm17; - s_regMapX86[X86_REG_XMM18] = RegsX86::xmm18; - s_regMapX86[X86_REG_YMM18] = RegsX86::xmm18; - s_regMapX86[X86_REG_ZMM18] = RegsX86::xmm18; - s_regMapX86[X86_REG_XMM19] = RegsX86::xmm19; - s_regMapX86[X86_REG_YMM19] = RegsX86::xmm19; - s_regMapX86[X86_REG_ZMM19] = RegsX86::xmm19; - s_regMapX86[X86_REG_XMM20] = RegsX86::xmm20; - s_regMapX86[X86_REG_YMM20] = RegsX86::xmm20; - s_regMapX86[X86_REG_ZMM20] = RegsX86::xmm20; - s_regMapX86[X86_REG_XMM21] = RegsX86::xmm21; - s_regMapX86[X86_REG_YMM21] = RegsX86::xmm21; - s_regMapX86[X86_REG_ZMM21] = RegsX86::xmm21; - s_regMapX86[X86_REG_XMM22] = RegsX86::xmm22; - s_regMapX86[X86_REG_YMM22] = RegsX86::xmm22; - s_regMapX86[X86_REG_ZMM22] = RegsX86::xmm22; - s_regMapX86[X86_REG_XMM23] = RegsX86::xmm23; - s_regMapX86[X86_REG_YMM23] = RegsX86::xmm23; - s_regMapX86[X86_REG_ZMM23] = RegsX86::xmm23; - s_regMapX86[X86_REG_XMM24] = RegsX86::xmm24; - s_regMapX86[X86_REG_YMM24] = RegsX86::xmm24; - s_regMapX86[X86_REG_ZMM24] = RegsX86::xmm24; - s_regMapX86[X86_REG_XMM25] = RegsX86::xmm25; - s_regMapX86[X86_REG_YMM25] = RegsX86::xmm25; - s_regMapX86[X86_REG_ZMM25] = RegsX86::xmm25; - s_regMapX86[X86_REG_XMM26] = RegsX86::xmm26; - s_regMapX86[X86_REG_YMM26] = RegsX86::xmm26; - s_regMapX86[X86_REG_ZMM26] = RegsX86::xmm26; - s_regMapX86[X86_REG_XMM27] = RegsX86::xmm27; - s_regMapX86[X86_REG_YMM27] = RegsX86::xmm27; - s_regMapX86[X86_REG_ZMM27] = RegsX86::xmm27; - s_regMapX86[X86_REG_XMM28] = RegsX86::xmm28; - s_regMapX86[X86_REG_YMM28] = RegsX86::xmm28; - s_regMapX86[X86_REG_ZMM28] = RegsX86::xmm28; - s_regMapX86[X86_REG_XMM29] = RegsX86::xmm29; - s_regMapX86[X86_REG_YMM29] = RegsX86::xmm29; - s_regMapX86[X86_REG_ZMM29] = RegsX86::xmm29; - s_regMapX86[X86_REG_XMM30] = RegsX86::xmm30; - s_regMapX86[X86_REG_YMM30] = RegsX86::xmm30; - s_regMapX86[X86_REG_ZMM30] = RegsX86::xmm30; - s_regMapX86[X86_REG_XMM31] = RegsX86::xmm31; - s_regMapX86[X86_REG_YMM31] = RegsX86::xmm31; - s_regMapX86[X86_REG_ZMM31] = RegsX86::xmm31; - s_regMapX86[X86_REG_K0] = RegsX86::k0; - s_regMapX86[X86_REG_K1] = RegsX86::k1; - s_regMapX86[X86_REG_K2] = RegsX86::k2; - s_regMapX86[X86_REG_K3] = RegsX86::k3; - s_regMapX86[X86_REG_K4] = RegsX86::k4; - s_regMapX86[X86_REG_K5] = RegsX86::k5; - s_regMapX86[X86_REG_K6] = RegsX86::k6; - s_regMapX86[X86_REG_K7] = RegsX86::k7; } static constexpr uint32_t PackCpuInfo( uint32_t cpuid ) @@ -734,386 +538,31 @@ void SourceView::ParseSource( const char* fileName, const Worker& worker, const } } -static bool IsJumpConditionalX86( const char* op ) -{ - static constexpr const char* branchX86[] = { - "je", "jne", "jg", "jge", "ja", "jae", "jl", "jle", "jb", "jbe", "jo", "jno", "jz", "jnz", "js", "jns", "jcxz", "jecxz", "jrcxz", "loop", "loope", - "loopne", "loopnz", "loopz", "jnle", "jnl", "jnge", "jng", "jnbe", "jnb", "jnae", "jna", "jc", "jnc", "jp", "jpe", "jnp", "jpo", nullptr - }; - auto ptr = branchX86; - while( *ptr ) if( strcmp( *ptr++, op ) == 0 ) return true; - return false; -} - bool SourceView::Disassemble( uint64_t symAddr, const Worker& worker ) { - m_asm.clear(); - m_locMap.clear(); - m_jumpTable.clear(); - m_jumpOut.clear(); + auto data = tracy::Disassemble( symAddr, worker ); + m_asm = std::move( data.lines ); + m_locMap = std::move( data.locMap ); + m_jumpTable = std::move( data.jumpTable ); + m_jumpOut = std::move( data.jumpOut ); + m_sourceFiles = std::move( data.sourceFiles ); + m_maxJumpLevel = data.maxJumpLevel; + m_disasmFail = data.disasmFail; + m_cpuArch = data.cpuArch; + m_codeLen = data.codeLen; + m_maxLine = data.maxLine; + m_maxMnemonicLen = data.maxMnemonicLen; + m_maxOperandLen = data.maxOperandLen; + m_maxAsmBytes = data.maxAsmBytes; + m_locationAddress.clear(); - m_maxJumpLevel = 0; m_asmSelected = -1; m_asmCountBase = -1; m_asmWidth = 0; - if( symAddr == 0 ) return false; - m_cpuArch = worker.GetCpuArch(); - if( m_cpuArch == CpuArchUnknown ) return false; - uint32_t len; - auto code = worker.GetSymbolCode( symAddr, len ); - if( !code ) return false; - m_disasmFail = -1; - csh handle; - cs_err rval = CS_ERR_ARCH; - switch( m_cpuArch ) - { - case CpuArchX86: - rval = cs_open( CS_ARCH_X86, CS_MODE_32, &handle ); - break; - case CpuArchX64: - rval = cs_open( CS_ARCH_X86, CS_MODE_64, &handle ); - break; - case CpuArchArm32: - rval = cs_open( CS_ARCH_ARM, CS_MODE_ARM, &handle ); - break; - case CpuArchArm64: - rval = cs_open( CS_ARCH_AARCH64, CS_MODE_ARM, &handle ); - break; - default: - assert( false ); - break; - } - if( rval != CS_ERR_OK ) return false; - cs_option( handle, CS_OPT_DETAIL, CS_OPT_ON ); - cs_option( handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL ); - cs_insn* insn; - size_t cnt = cs_disasm( handle, (const uint8_t*)code, len, symAddr, 0, &insn ); - if( cnt > 0 ) - { - if( insn[cnt-1].address - symAddr + insn[cnt-1].size < len ) m_disasmFail = insn[cnt-1].address - symAddr; - int bytesMax = 0; - int mLenMax = 0; - int oLenMax = 0; - m_asm.reserve( cnt ); - for( size_t i=0; i= symAddr && jumpAddr < symAddr + len ) - { - auto fit = std::lower_bound( insn, insn+cnt, jumpAddr, []( const auto& l, const auto& r ) { return l.address < r; } ); - if( fit != insn+cnt && fit->address == jumpAddr ) - { - const auto min = std::min( jumpAddr, op.address ); - const auto max = std::max( jumpAddr, op.address ); - auto it = m_jumpTable.find( jumpAddr ); - if( it == m_jumpTable.end() ) - { - m_jumpTable.emplace( jumpAddr, JumpData { min, max, 0, { op.address } } ); - } - else - { - if( it->second.min > min ) it->second.min = min; - else if( it->second.max < max ) it->second.max = max; - it->second.source.emplace_back( op.address ); - } - } - else - { - jumpAddr = 0; - } - } - else - { - m_jumpOut.emplace( op.address ); - } - } - std::vector params; - switch( m_cpuArch ) - { - case CpuArchX86: - case CpuArchX64: - for( uint8_t i=0; ix86.op_count == 2 ); - assert( op.detail->x86.operands[1].type == X86_OP_MEM ); - auto& mem = op.detail->x86.operands[1].mem; - if( mem.base == X86_REG_INVALID ) - { - if( mem.index == X86_REG_INVALID ) - { - leaData = LeaData::d; - } - else - { - leaData = mem.disp == 0 ? LeaData::i : LeaData::id; - } - } - else if( mem.base == X86_REG_RIP ) - { - leaData = mem.disp == 0 ? LeaData::r : LeaData::rd; - } - else - { - if( mem.index == X86_REG_INVALID ) - { - leaData = mem.disp == 0 ? LeaData::b : LeaData::bd; - } - else - { - leaData = mem.disp == 0 ? LeaData::bi : LeaData::bid; - } - } - } - m_asm.emplace_back( AsmLine { op.address, jumpAddr, op.mnemonic, op.op_str, (uint8_t)op.size, leaData, opType, jumpConditional, std::move( params ) } ); - const auto& operands = m_asm.back().operands; - m_asm.back().opTokens = m_tokenizer.TokenizeAsm( operands.c_str(), operands.c_str() + operands.size() ); -#if CS_API_MAJOR >= 4 - auto& entry = m_asm.back(); - cs_regs read, write; - uint8_t rcnt, wcnt; - cs_regs_access( handle, &op, read, &rcnt, write, &wcnt ); - int idx; - switch( m_cpuArch ) - { - case CpuArchX86: - case CpuArchX64: - assert( rcnt < sizeof( entry.readX86 ) ); - assert( wcnt < sizeof( entry.writeX86 ) ); - idx = 0; - for( int i=0; i mLenMax ) mLenMax = mLen; - const auto oLen = (int)strlen( op.op_str ); - if( oLen > oLenMax ) oLenMax = oLen; - if( op.size > bytesMax ) bytesMax = op.size; - - uint32_t mLineMax = 0; - uint32_t srcline; - const auto srcidx = worker.GetLocationForAddress( op.address, srcline ); - if( srcidx.Active() ) - { - if( srcline > mLineMax ) mLineMax = srcline; - const auto idx = srcidx.Idx(); - auto sit = m_sourceFiles.find( idx ); - if( sit == m_sourceFiles.end() ) m_sourceFiles.emplace( idx, srcline ); - } - char tmp[16]; - sprintf( tmp, "%" PRIu32, mLineMax ); - m_maxLine = strlen( tmp ) + 1; - } - cs_free( insn, cnt ); - m_maxMnemonicLen = mLenMax + 1; - m_maxOperandLen = oLenMax + 1; - m_maxAsmBytes = bytesMax; - if( !m_jumpTable.empty() ) - { - struct JumpRange - { - uint64_t target; - uint64_t len; - }; - std::vector jumpRange; - jumpRange.reserve( m_jumpTable.size() ); - for( auto& v : m_jumpTable ) - { - pdqsort_branchless( v.second.source.begin(), v.second.source.end() ); - jumpRange.emplace_back( JumpRange { v.first, v.second.max - v.second.min } ); - } - pdqsort_branchless( jumpRange.begin(), jumpRange.end(), []( const auto& l, const auto& r ) { return l.len < r.len; } ); - std::vector>> levelRanges; - for( auto& v : jumpRange ) - { - auto it = m_jumpTable.find( v.target ); - assert( it != m_jumpTable.end() ); - size_t level = 0; - for(;;) - { - assert( levelRanges.size() >= level ); - if( levelRanges.size() == level ) - { - it->second.level = level; - levelRanges.push_back( { { it->second.min, it->second.max } } ); - break; - } - else - { - bool validFit = true; - auto& lr = levelRanges[level]; - for( auto& range : lr ) - { - assert( !( it->second.min >= range.first && it->second.max <= range.second ) ); - if( it->second.min <= range.second && it->second.max >= range.first ) - { - validFit = false; - break; - } - } - if( validFit ) - { - it->second.level = level; - lr.emplace_back( it->second.min, it->second.max ); - break; - } - level++; - } - } - if( level > m_maxJumpLevel ) m_maxJumpLevel = level; - } - - uint32_t locNum = 0; - for( auto& v : m_asm ) - { - if( m_jumpTable.find( v.addr ) != m_jumpTable.end() ) - { - m_locMap.emplace( v.addr, locNum++ ); - } - } - } - } - cs_close( &handle ); - m_codeLen = len; ResetAsm(); - return true; + + return !m_asm.empty(); } void SourceView::Render( Worker& worker, View& view ) @@ -2510,7 +1959,7 @@ static int PrintHexBytes( const uint8_t* bytes, size_t len, CpuArchitecture arch } } -std::tuple SourceView::GetJumpRange( const JumpData& jump ) +std::tuple SourceView::GetJumpRange( const AsmJumpData& jump ) { size_t minIdx = 0, maxIdx = 0; size_t i; @@ -4573,17 +4022,17 @@ void SourceView::RenderAsmLine( AsmLine& line, const AddrStat& ipcnt, const Addr if( opdesc != 0 ) { ImGui::TextUnformatted( OpDescList[opdesc] ); - if( line.opType == OpType::Privileged ) + if( line.opType == AsmOpType::Privileged ) { ImGui::SameLine(); ImGui::Spacing(); ImGui::SameLine(); - TextColoredUnformatted( AsmOpTypeColors[(int)OpType::Privileged], "privileged" ); + TextColoredUnformatted( AsmOpTypeColors[(int)AsmOpType::Privileged], "privileged" ); } } - else if( line.opType == OpType::Privileged ) + else if( line.opType == AsmOpType::Privileged ) { - TextColoredUnformatted( AsmOpTypeColors[(int)OpType::Privileged], "Privileged" ); + TextColoredUnformatted( AsmOpTypeColors[(int)AsmOpType::Privileged], "Privileged" ); } if( jumpName ) { diff --git a/profiler/src/profiler/TracySourceView.hpp b/profiler/src/profiler/TracySourceView.hpp index a250b9d2..4a9bd964 100644 --- a/profiler/src/profiler/TracySourceView.hpp +++ b/profiler/src/profiler/TracySourceView.hpp @@ -2,13 +2,13 @@ #define __TRACYSOURCEVIEW_HPP__ #include -#include #include #include #include "tracy_robin_hood.h" #include "TracyCharUtil.hpp" #include "TracyDecayValue.hpp" +#include "TracyDisassembly.hpp" #include "TracySourceContents.hpp" #include "TracySourceTokenizer.hpp" #include "../public/common/TracyForceInline.hpp" @@ -27,18 +27,6 @@ struct CallstackFrameData; class SourceView { public: - enum class RegsX86 : uint8_t - { - invalid, flags, - rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, r8, r9, r10, r11, r12, r13, r14, r15, - mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, - xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, - xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, xmm16, xmm17, xmm18, xmm19, - xmm20, xmm21, xmm22, xmm23, xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, - xmm30, xmm31, k0, k1, k2, k3, k4, k5, k6, k7, - NUMBER_OF_ENTRIES - }; - enum class CostType { SampleCount, @@ -53,73 +41,12 @@ public: }; private: - struct AsmOpParams - { - uint8_t type; - uint16_t width; - }; - - enum class LeaData : uint8_t - { - none, - b, - bd, - bi, - bid, - d, - i, - id, - r, - rd - }; - static constexpr int ReadBit = 0x100; static constexpr int WriteBit = 0x200; static constexpr int ReuseBit = 0x400; static constexpr int RegMask = 0x0FF; static constexpr int FlagMask = 0xF00; - enum class OpType : uint8_t - { - None, - Jump, - Branch, - Call, - Ret, - Privileged - }; - - struct AsmLine - { - uint64_t addr; - uint64_t jumpAddr; - std::string mnemonic; - std::string operands; - uint8_t len; - LeaData leaData; - OpType opType; - bool jumpConditional; - std::vector params; - std::vector opTokens; - union - { - RegsX86 readX86[12]; - }; - union - { - RegsX86 writeX86[20]; - }; - uint16_t regData[20]; - }; - - struct JumpData - { - uint64_t min; - uint64_t max; - size_t level; - std::vector source; - }; - enum { DisplaySource, @@ -212,7 +139,7 @@ private: const std::vector* GetAddressesForLocation( uint32_t fileStringIdx, uint32_t line, const Worker& worker ); tracy_force_inline float CalcJumpSeparation( float scale ); - std::tuple GetJumpRange( const JumpData& jump ); + std::tuple GetJumpRange( const AsmJumpData& jump ); void AttachRangeToLlm( size_t start, size_t stop, Worker& worker, View& view, const AddrStatData& as ); @@ -254,7 +181,7 @@ private: std::vector m_asm; unordered_flat_map m_locMap; - unordered_flat_map m_jumpTable; + unordered_flat_map m_jumpTable; unordered_flat_set m_jumpOut; size_t m_maxJumpLevel; bool m_showJumps; @@ -284,8 +211,6 @@ private: float m_asmWidth; float m_jumpOffset; - Tokenizer m_tokenizer; - struct { uint32_t file = 0;