From 1a8461fdd573639edb569491619591552414ea2b Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Fri, 28 Jul 2023 12:14:21 -0400 Subject: [PATCH] Display the absolute address for relative jumps on x86 yaxpeax doesn't have support for doing this natively so just shim it on top. --- fixtures/snapshots/asm_x86_64.txt | 2 +- samply-api/src/asm/mod.rs | 95 ++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/fixtures/snapshots/asm_x86_64.txt b/fixtures/snapshots/asm_x86_64.txt index d77c33fde..8b544afbe 100644 --- a/fixtures/snapshots/asm_x86_64.txt +++ b/fixtures/snapshots/asm_x86_64.txt @@ -1 +1 @@ -{"startAddress":"0x17a20","size":"0x3d","arch":"x86_64","syntax":["Intel","C style"],"instructions":[[0,"jl $-0x64","if /* signed */ less(rflags) then jmp $-0x64"],[2,"add eax, dword [rax]","eax += [rax]"],[4,"mov edx, 0x38","edx = 0x38"],[9,"mov rcx, r15","rcx = r15"],[12,"call 0x39c6f","0x39c6f = call(0x39c6f)"],[17,"xor eax, eax","eax ^= eax"],[19,"jmp $+0x9a","jmp $+0x9a"],[24,"mov rbx, qword [r15]","rbx = [r15]"],[27,"cmp rbx, rax","rflags = flags(rbx - rax)"],[30,"jz $+0x35","if zero(rflags) then jmp $+0x35"],[32,"mov rdx, qword [r15 + 0x8]","rdx = [r15 + 0x8]"],[36,"mov qword [rdx], rbx","[rdx] = rbx"],[39,"mov rdx, qword [rbx + 0x8]","rdx = [rbx + 0x8]"],[43,"mov qword [rdx], rax","[rdx] = rax"],[46,"mov rdx, qword [rax + 0x8]","rdx = [rax + 0x8]"],[50,"mov qword [rdx], r15","[rdx] = r15"],[53,"mov rdx, qword [rax + 0x8]","rdx = [rax + 0x8]"],[57,"mov rbp, qword [rbx + 0x8]","rbp = [rbx + 0x8]"]]} \ No newline at end of file +{"startAddress":"0x17a20","size":"0x3d","arch":"x86_64","syntax":["Intel","C style"],"instructions":[[0,"jl 0x179be","jl 0x179be"],[2,"add eax, dword [rax]","eax += [rax]"],[4,"mov edx, 0x38","edx = 0x38"],[9,"mov rcx, r15","rcx = r15"],[12,"call 0x39c6f","0x39c6f = call(0x39c6f)"],[17,"xor eax, eax","eax ^= eax"],[19,"jmp 0x17ad2","jmp 0x17ad2"],[24,"mov rbx, qword [r15]","rbx = [r15]"],[27,"cmp rbx, rax","rflags = flags(rbx - rax)"],[30,"jz 0x17a75","jz 0x17a75"],[32,"mov rdx, qword [r15 + 0x8]","rdx = [r15 + 0x8]"],[36,"mov qword [rdx], rbx","[rdx] = rbx"],[39,"mov rdx, qword [rbx + 0x8]","rdx = [rbx + 0x8]"],[43,"mov qword [rdx], rax","[rdx] = rax"],[46,"mov rdx, qword [rax + 0x8]","rdx = [rax + 0x8]"],[50,"mov qword [rdx], r15","[rdx] = r15"],[53,"mov rdx, qword [rax + 0x8]","rdx = [rax + 0x8]"],[57,"mov rbp, qword [rbx + 0x8]","rbp = [rbx + 0x8]"]]} \ No newline at end of file diff --git a/samply-api/src/asm/mod.rs b/samply-api/src/asm/mod.rs index d7ab30cae..09b3c3de8 100644 --- a/samply-api/src/asm/mod.rs +++ b/samply-api/src/asm/mod.rs @@ -5,7 +5,8 @@ use samply_symbols::{ FileAndPathHelperError, LibraryInfo, SymbolManager, }; use serde_json::json; -use yaxpeax_arch::{Arch, DecodeError, Reader, U8Reader}; +use yaxpeax_arch::{Arch, DecodeError, LengthedInstruction, Reader, U8Reader}; +use yaxpeax_x86::amd64::{Opcode, Operand}; use crate::asm::response_json::DecodedInstruction; @@ -192,7 +193,8 @@ trait InstructionDecoding: Arch { const SYNTAX: &'static [&'static str]; const ADJUST_BY_AFTER_ERROR: usize; fn make_decoder() -> Self::Decoder; - fn stringify_inst(offset: u32, inst: Self::Instruction) -> DecodedInstruction; + fn stringify_inst(rel_address: u32, offset: u32, inst: Self::Instruction) + -> DecodedInstruction; } impl InstructionDecoding for yaxpeax_x86::amd64::Arch { @@ -204,15 +206,70 @@ impl InstructionDecoding for yaxpeax_x86::amd64::Arch { yaxpeax_x86::amd64::InstDecoder::default() } - fn stringify_inst(offset: u32, inst: Self::Instruction) -> DecodedInstruction { + fn stringify_inst( + rel_address: u32, + offset: u32, + inst: Self::Instruction, + ) -> DecodedInstruction { + let (mut intel_insn, mut c_insn) = ( + inst.display_with(yaxpeax_x86::amd64::DisplayStyle::Intel) + .to_string(), + inst.display_with(yaxpeax_x86::amd64::DisplayStyle::C) + .to_string(), + ); + + fn is_relative_branch(opcode: Opcode) -> bool { + matches!( + opcode, + Opcode::JMP + | Opcode::JRCXZ + | Opcode::LOOP + | Opcode::LOOPZ + | Opcode::LOOPNZ + | Opcode::JO + | Opcode::JNO + | Opcode::JB + | Opcode::JNB + | Opcode::JZ + | Opcode::JNZ + | Opcode::JNA + | Opcode::JA + | Opcode::JS + | Opcode::JNS + | Opcode::JP + | Opcode::JNP + | Opcode::JL + | Opcode::JGE + | Opcode::JLE + | Opcode::JG + ) + } + + if is_relative_branch(inst.opcode()) { + match inst.operand(0) { + Operand::ImmediateI8(rel) => { + let dest = rel_address as i64 + + offset as i64 + + inst.len().to_const() as i64 + + rel as i64; + intel_insn = format!("{} 0x{:x}", inst.opcode(), dest); + c_insn = intel_insn.clone(); + } + Operand::ImmediateI32(rel) => { + let dest = rel_address as i64 + + offset as i64 + + inst.len().to_const() as i64 + + rel as i64; + intel_insn = format!("{} 0x{:x}", inst.opcode(), dest); + c_insn = intel_insn.clone(); + } + _ => {} + }; + } + DecodedInstruction { offset, - decoded_string_per_syntax: vec![ - inst.display_with(yaxpeax_x86::amd64::DisplayStyle::Intel) - .to_string(), - inst.display_with(yaxpeax_x86::amd64::DisplayStyle::C) - .to_string(), - ], + decoded_string_per_syntax: vec![intel_insn, c_insn], } } } @@ -226,7 +283,11 @@ impl InstructionDecoding for yaxpeax_x86::protected_mode::Arch { yaxpeax_x86::protected_mode::InstDecoder::default() } - fn stringify_inst(offset: u32, inst: Self::Instruction) -> DecodedInstruction { + fn stringify_inst( + _rel_address: u32, + offset: u32, + inst: Self::Instruction, + ) -> DecodedInstruction { DecodedInstruction { offset, decoded_string_per_syntax: vec![inst.to_string()], @@ -243,7 +304,11 @@ impl InstructionDecoding for yaxpeax_arm::armv8::a64::ARMv8 { yaxpeax_arm::armv8::a64::InstDecoder::default() } - fn stringify_inst(offset: u32, inst: Self::Instruction) -> DecodedInstruction { + fn stringify_inst( + _rel_address: u32, + offset: u32, + inst: Self::Instruction, + ) -> DecodedInstruction { DecodedInstruction { offset, decoded_string_per_syntax: vec![inst.to_string()], @@ -271,7 +336,11 @@ impl InstructionDecoding for yaxpeax_arm::armv7::ARMv7 { yaxpeax_arm::armv7::InstDecoder::default_thumb() } - fn stringify_inst(offset: u32, inst: Self::Instruction) -> DecodedInstruction { + fn stringify_inst( + _rel_address: u32, + offset: u32, + inst: Self::Instruction, + ) -> DecodedInstruction { DecodedInstruction { offset, decoded_string_per_syntax: vec![inst.to_string()], @@ -300,7 +369,7 @@ where let before = u64::from(reader.total_offset()) as u32; match decoder.decode(&mut reader) { Ok(inst) => { - instructions.push(A::stringify_inst(offset, inst)); + instructions.push(A::stringify_inst(rel_address, offset, inst)); let after = u64::from(reader.total_offset()) as u32; offset += after - before; }