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.
This commit is contained in:
Bartosz Taudul
2026-05-11 01:30:28 +02:00
parent 1dcad83790
commit beec259520
5 changed files with 732 additions and 652 deletions
+1
View File
@@ -59,6 +59,7 @@ set(SERVER_FILES
TracyBadVersion.cpp
TracyColor.cpp
TracyConfig.cpp
TracyDisassembly.cpp
TracyEmbed.cpp
TracyEventDebug.cpp
TracyFileselector.cpp
+592
View File
@@ -0,0 +1,592 @@
#include <capstone.h>
#include <string.h>
#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<cnt; i++ )
{
const auto& op = insn[i];
const auto& detail = *op.detail;
bool hasJump = false;
bool jumpConditional = false;
AsmOpType opType = AsmOpType::None;
for( auto j=0; j<detail.groups_count; j++ )
{
if( detail.groups[j] == CS_GRP_JUMP || detail.groups[j] == CS_GRP_CALL || detail.groups[j] == CS_GRP_RET )
{
hasJump = true;
break;
}
}
for( auto j=0; j<detail.groups_count; j++ )
{
if( detail.groups[j] == CS_GRP_JUMP && opType < AsmOpType::Jump ) opType = AsmOpType::Jump;
else if( detail.groups[j] == CS_GRP_BRANCH_RELATIVE && opType < AsmOpType::Branch ) opType = AsmOpType::Branch;
else if( detail.groups[j] == CS_GRP_CALL && opType < AsmOpType::Call ) opType = AsmOpType::Call;
else if( detail.groups[j] == CS_GRP_RET && opType < AsmOpType::Ret ) opType = AsmOpType::Ret;
else if( detail.groups[j] == CS_GRP_PRIVILEGE && opType < AsmOpType::Privileged )
{
opType = AsmOpType::Privileged;
break;
}
}
uint64_t jumpAddr = 0;
if( hasJump )
{
switch( data.cpuArch )
{
case CpuArchX86:
case CpuArchX64:
if( detail.x86.op_count == 1 && detail.x86.operands[0].type == X86_OP_IMM )
{
jumpAddr = (uint64_t)detail.x86.operands[0].imm;
}
jumpConditional = IsJumpConditionalX86( op.mnemonic );
break;
case CpuArchArm32:
if( detail.arm.op_count == 1 && detail.arm.operands[0].type == ARM_OP_IMM )
{
jumpAddr = (uint64_t)detail.arm.operands[0].imm;
}
break;
case CpuArchArm64:
if( detail.aarch64.op_count == 1 && detail.aarch64.operands[0].type == AARCH64_OP_IMM )
{
jumpAddr = (uint64_t)detail.aarch64.operands[0].imm;
}
break;
default:
assert( false );
break;
}
if( jumpAddr >= 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<AsmOpParams> params;
switch( data.cpuArch )
{
case CpuArchX86:
case CpuArchX64:
for( uint8_t i=0; i<detail.x86.op_count; i++ )
{
uint8_t type = 0;
switch( detail.x86.operands[i].type )
{
case X86_OP_IMM:
type = 0;
break;
case X86_OP_REG:
type = 1;
break;
case X86_OP_MEM:
type = 2;
break;
default:
assert( false );
break;
}
params.emplace_back( AsmOpParams { type, uint16_t( detail.x86.operands[i].size * 8 ) } );
}
break;
case CpuArchArm32:
for( uint8_t i=0; i<detail.arm.op_count; i++ )
{
uint8_t type = 0;
switch( detail.arm.operands[i].type )
{
case ARM_OP_IMM:
type = 0;
break;
case ARM_OP_REG:
type = 1;
break;
case ARM_OP_MEM:
type = 2;
break;
default:
type = 255;
break;
}
params.emplace_back( AsmOpParams { type, 0 } );
}
break;
case CpuArchArm64:
for( uint8_t i=0; i<detail.aarch64.op_count; i++ )
{
uint8_t type = 0;
switch( detail.aarch64.operands[i].type )
{
case AARCH64_OP_IMM:
type = 0;
break;
case AARCH64_OP_REG:
type = 1;
break;
case AARCH64_OP_MEM:
type = 2;
break;
default:
type = 255;
break;
}
params.emplace_back( AsmOpParams { type, 0 } );
}
break;
default:
assert( false );
break;
}
AsmLeaData leaData = AsmLeaData::none;
if( ( data.cpuArch == CpuArchX64 || data.cpuArch == CpuArchX86 ) && op.id == X86_INS_LEA )
{
assert( op.detail->x86.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<rcnt; i++ )
{
if( s_regMapX86[read[i]] != RegsX86::invalid ) entry.readX86[idx++] = s_regMapX86[read[i]];
entry.readX86[idx] = RegsX86::invalid;
}
idx = 0;
for( int i=0; i<wcnt; i++ )
{
if( s_regMapX86[write[i]] != RegsX86::invalid ) entry.writeX86[idx++] = s_regMapX86[write[i]];
entry.writeX86[idx] = RegsX86::invalid;
}
break;
default:
break;
}
#endif
const auto mLen = (int)strlen( op.mnemonic );
if( mLen > 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;
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<std::vector<std::pair<uint64_t, uint64_t>>> 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;
}
}
+113
View File
@@ -0,0 +1,113 @@
#ifndef __TRACYDISASSEMBLY_HPP__
#define __TRACYDISASSEMBLY_HPP__
#include <stdint.h>
#include <string>
#include <vector>
#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<uint64_t> 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<AsmOpParams> params;
std::vector<Tokenizer::AsmToken> opTokens;
union
{
RegsX86 readX86[12];
};
union
{
RegsX86 writeX86[20];
};
uint16_t regData[20];
};
struct DisasmData
{
std::vector<AsmLine> lines;
unordered_flat_map<uint64_t, uint32_t> locMap;
unordered_flat_map<uint64_t, AsmJumpData> jumpTable;
unordered_flat_set<uint64_t> jumpOut;
unordered_flat_map<uint32_t, uint32_t> 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
+23 -574
View File
@@ -4,8 +4,6 @@
#include <sstream>
#include <stdio.h>
#include <capstone.h>
#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<cnt; i++ )
{
const auto& op = insn[i];
const auto& detail = *op.detail;
bool hasJump = false;
bool jumpConditional = false;
OpType opType = OpType::None;
for( auto j=0; j<detail.groups_count; j++ )
{
if( detail.groups[j] == CS_GRP_JUMP || detail.groups[j] == CS_GRP_CALL || detail.groups[j] == CS_GRP_RET )
{
hasJump = true;
break;
}
}
for( auto j=0; j<detail.groups_count; j++ )
{
if( detail.groups[j] == CS_GRP_JUMP && opType < OpType::Jump ) opType = OpType::Jump;
else if( detail.groups[j] == CS_GRP_BRANCH_RELATIVE && opType < OpType::Branch ) opType = OpType::Branch;
else if( detail.groups[j] == CS_GRP_CALL && opType < OpType::Call ) opType = OpType::Call;
else if( detail.groups[j] == CS_GRP_RET && opType < OpType::Ret ) opType = OpType::Ret;
else if( detail.groups[j] == CS_GRP_PRIVILEGE && opType < OpType::Privileged )
{
opType = OpType::Privileged;
break;
}
}
uint64_t jumpAddr = 0;
if( hasJump )
{
switch( m_cpuArch )
{
case CpuArchX86:
case CpuArchX64:
if( detail.x86.op_count == 1 && detail.x86.operands[0].type == X86_OP_IMM )
{
jumpAddr = (uint64_t)detail.x86.operands[0].imm;
}
jumpConditional = IsJumpConditionalX86( op.mnemonic );
break;
case CpuArchArm32:
if( detail.arm.op_count == 1 && detail.arm.operands[0].type == ARM_OP_IMM )
{
jumpAddr = (uint64_t)detail.arm.operands[0].imm;
}
break;
case CpuArchArm64:
if( detail.aarch64.op_count == 1 && detail.aarch64.operands[0].type == AARCH64_OP_IMM )
{
jumpAddr = (uint64_t)detail.aarch64.operands[0].imm;
}
break;
default:
assert( false );
break;
}
if( jumpAddr >= 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<AsmOpParams> params;
switch( m_cpuArch )
{
case CpuArchX86:
case CpuArchX64:
for( uint8_t i=0; i<detail.x86.op_count; i++ )
{
uint8_t type = 0;
switch( detail.x86.operands[i].type )
{
case X86_OP_IMM:
type = 0;
break;
case X86_OP_REG:
type = 1;
break;
case X86_OP_MEM:
type = 2;
break;
default:
assert( false );
break;
}
params.emplace_back( AsmOpParams { type, uint16_t( detail.x86.operands[i].size * 8 ) } );
}
break;
case CpuArchArm32:
for( uint8_t i=0; i<detail.arm.op_count; i++ )
{
uint8_t type = 0;
switch( detail.arm.operands[i].type )
{
case ARM_OP_IMM:
type = 0;
break;
case ARM_OP_REG:
type = 1;
break;
case ARM_OP_MEM:
type = 2;
break;
default:
type = 255;
break;
}
params.emplace_back( AsmOpParams { type, 0 } );
}
break;
case CpuArchArm64:
for( uint8_t i=0; i<detail.aarch64.op_count; i++ )
{
uint8_t type = 0;
switch( detail.aarch64.operands[i].type )
{
case AARCH64_OP_IMM:
type = 0;
break;
case AARCH64_OP_REG:
type = 1;
break;
case AARCH64_OP_MEM:
type = 2;
break;
default:
type = 255;
break;
}
params.emplace_back( AsmOpParams { type, 0 } );
}
break;
default:
assert( false );
break;
}
LeaData leaData = LeaData::none;
if( ( m_cpuArch == CpuArchX64 || m_cpuArch == CpuArchX86 ) && op.id == X86_INS_LEA )
{
assert( op.detail->x86.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<rcnt; i++ )
{
if( s_regMapX86[read[i]] != RegsX86::invalid ) entry.readX86[idx++] = s_regMapX86[read[i]];
entry.readX86[idx] = RegsX86::invalid;
}
idx = 0;
for( int i=0; i<wcnt; i++ )
{
if( s_regMapX86[write[i]] != RegsX86::invalid ) entry.writeX86[idx++] = s_regMapX86[write[i]];
entry.writeX86[idx] = RegsX86::invalid;
}
break;
default:
break;
}
#endif
const auto mLen = (int)strlen( op.mnemonic );
if( mLen > 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;
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<std::vector<std::pair<uint64_t, uint64_t>>> 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<size_t, size_t> SourceView::GetJumpRange( const JumpData& jump )
std::tuple<size_t, size_t> 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 )
{
+3 -78
View File
@@ -2,13 +2,13 @@
#define __TRACYSOURCEVIEW_HPP__
#include <limits>
#include <string>
#include <tuple>
#include <vector>
#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<AsmOpParams> params;
std::vector<Tokenizer::AsmToken> 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<uint64_t> source;
};
enum
{
DisplaySource,
@@ -212,7 +139,7 @@ private:
const std::vector<uint64_t>* GetAddressesForLocation( uint32_t fileStringIdx, uint32_t line, const Worker& worker );
tracy_force_inline float CalcJumpSeparation( float scale );
std::tuple<size_t, size_t> GetJumpRange( const JumpData& jump );
std::tuple<size_t, size_t> 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<AsmLine> m_asm;
unordered_flat_map<uint64_t, uint32_t> m_locMap;
unordered_flat_map<uint64_t, JumpData> m_jumpTable;
unordered_flat_map<uint64_t, AsmJumpData> m_jumpTable;
unordered_flat_set<uint64_t> 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;