Skip to content

Commit

Permalink
adds tracing for AArch64
Browse files Browse the repository at this point in the history
Some parts of this code are shared with the 32-bit arm, specifically
tracing of flags and conditions.
For AArch64, we store operands only for the flags that are actually
used, as opposed to existing arm code, which always dumps all of them
unconditionally. To account for this change, loaded_cpsr and store_cpsr
have been refactored to now be bitfields indicating the individual
flags, rather than being just single booleans.
Old code just sets them to TRACE_CPSR_ALL and can be made more
fine-grained successively in the future if desired.
  • Loading branch information
thestr4ng3r committed Mar 26, 2022
1 parent 281acb4 commit 03d66a8
Show file tree
Hide file tree
Showing 9 changed files with 491 additions and 243 deletions.
8 changes: 5 additions & 3 deletions include/tracewrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ void qemu_trace_set_mode(const char *mode_str);
void qemu_trace_endframe(CPUArchState *env, target_ulong pc, target_ulong size);
void qemu_trace_finish(uint32_t exit_code);

OperandInfo * load_store_reg(target_ulong reg, target_ulong val, int ls);
OperandInfo * load_store_reg64(target_ulong reg, uint64_t val, int ls);
OperandInfo * load_store_mem(uint32_t addr, int ls, const void *data, size_t data_size);
OperandInfo * load_store_reg(uint32_t reg, uint32_t val, int ls);
OperandInfo * load_store_reg64(uint32_t reg, uint64_t val, int ls);
OperandInfo * load_store_mem(uint64_t addr, int ls, const void *data, size_t data_size);

#define REG_EFLAGS 66
#define REG_LO 33
Expand All @@ -65,4 +65,6 @@ OperandInfo * load_store_mem(uint32_t addr, int ls, const void *data, size_t dat

#define REG_S0 100 // s1 is REG_S0 + 1 and so on

#define REG64_D0 100 // d1 is REG_D0 + 1 and so on

#define SEG_BIT 8
6 changes: 6 additions & 0 deletions linux-user/aarch64/trace_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "frame_arch.h"

const uint64_t frame_arch = frame_arch_aarch64;
const uint64_t frame_mach = frame_mach_aarch64;
19 changes: 15 additions & 4 deletions target/arm/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ DEF_HELPER_3(cpsr_write, void, env, i32, i32)
DEF_HELPER_2(cpsr_write_eret, void, env, i32)
DEF_HELPER_1(cpsr_read, i32, env)

#define TRACE_CPSR_NF (1 << 0)
#define TRACE_CPSR_ZF (1 << 1)
#define TRACE_CPSR_CF (1 << 2)
#define TRACE_CPSR_VF (1 << 3)
#define TRACE_CPSR_QF (1 << 4)
#define TRACE_CPSR_GE (1 << 5)
#define TRACE_CPSR_ALL 0xffffffff
#ifdef HAS_TRACEWRAP
DEF_HELPER_1(trace_newframe, void, i32)
DEF_HELPER_3(trace_endframe, void, env, i32, i32)
Expand All @@ -69,11 +76,15 @@ DEF_HELPER_2(trace_load_reg, void, i32, i32)
DEF_HELPER_2(trace_store_reg, void, i32, i32)
DEF_HELPER_2(trace_load_reg64, void, i32, i64)
DEF_HELPER_2(trace_store_reg64, void, i32, i64)
DEF_HELPER_3(trace_cpsr_write, void, env, i32, i32)
DEF_HELPER_1(trace_cpsr_read, i32, env)
DEF_HELPER_1(log_read_cpsr, void, env)
DEF_HELPER_1(log_store_cpsr, void, env)
DEF_HELPER_1(trace_mode, void, ptr)
DEF_HELPER_2(trace_read_cpsr, void, env, i32)
DEF_HELPER_2(trace_store_cpsr, void, env, i32)
#ifdef TARGET_AARCH64
DEF_HELPER_1(trace_newframe_64, void, i64)
DEF_HELPER_2(trace_endframe_64, void, env, i64)
DEF_HELPER_4(trace_ld64_64, void, env, i64, i64, i32)
DEF_HELPER_4(trace_st64_64, void, env, i64, i64, i32)
#endif
#endif //HAS_TRACEWRAP

DEF_HELPER_3(v7m_msr, void, env, i32, i32)
Expand Down
247 changes: 116 additions & 131 deletions target/arm/trace_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,15 @@
#include "exec/helper-proto.h"
#include "tcg/tcg.h"

uint32_t HELPER(trace_cpsr_read)(CPUARMState *env) {
uint32_t res = cpsr_read(env) & ~CPSR_EXEC;
OperandInfo * oi = load_store_reg(REG_CPSR, res, 0);
qemu_trace_add_operand(oi, 0x1);
return res;
}

void HELPER(trace_cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask) {
OperandInfo * oi = load_store_reg(REG_CPSR, val, 1);
qemu_trace_add_operand(oi, 0x2);
}

void HELPER(trace_newframe)(target_ulong pc) {
void HELPER(trace_newframe)(uint32_t pc) {
qemu_trace_newframe(pc, 0);
}

void HELPER(trace_endframe)(CPUARMState *env, target_ulong old_pc, uint32_t size) {
void HELPER(trace_endframe)(CPUARMState *env, uint32_t old_pc, uint32_t size) {
qemu_trace_endframe(env, old_pc, size);
}

OperandInfo *load_store_mem(uint32_t addr, int ls, const void *data, size_t data_size) {
OperandInfo *load_store_mem(uint64_t addr, int ls, const void *data, size_t data_size) {
MemOperand * mo = g_new(MemOperand, 1);
mem_operand__init(mo);

Expand Down Expand Up @@ -58,7 +46,7 @@ OperandInfo *load_store_mem(uint32_t addr, int ls, const void *data, size_t data
static OperandInfo *build_load_store_reg_op(char *name, int ls, const void *data, size_t data_size) {
RegOperand * ro = g_new(RegOperand, 1);
reg_operand__init(ro);
ro->name = name;
ro->name = name;

OperandInfoSpecific *ois = g_new(OperandInfoSpecific, 1);
operand_info_specific__init(ois);
Expand All @@ -84,76 +72,68 @@ static OperandInfo *build_load_store_reg_op(char *name, int ls, const void *data
}

OperandInfo * load_store_reg(uint32_t reg, uint32_t val, int ls) {
char *name;
if (reg >= REG_S0) {
name = g_strdup_printf("S%u", (unsigned int)(reg - REG_S0));
} else {
switch (reg) {
case REG_SP: name = g_strdup("SP"); break;
case REG_LR: name = g_strdup("LR"); break;
case REG_PC: name = g_strdup("PC"); break;
case REG_NF: name = g_strdup("NF"); break;
case REG_ZF: name = g_strdup("ZF"); break;
case REG_CF: name = g_strdup("CF"); break;
case REG_VF: name = g_strdup("VF"); break;
case REG_QF: name = g_strdup("QF"); break;
case REG_GE: name = g_strdup("GE"); break;
default: name = g_strdup_printf("R%u", (unsigned int)reg); break;
}
}
return build_load_store_reg_op(name, ls, &val, sizeof(val));
char *name;
if (reg >= REG_S0) {
name = g_strdup_printf("S%u", (unsigned int)(reg - REG_S0));
} else {
switch (reg) {
case REG_SP: name = g_strdup("SP"); break;
case REG_LR: name = g_strdup("LR"); break;
case REG_PC: name = g_strdup("PC"); break;
case REG_NF: name = g_strdup("NF"); break;
case REG_ZF: name = g_strdup("ZF"); break;
case REG_CF: name = g_strdup("CF"); break;
case REG_VF: name = g_strdup("VF"); break;
case REG_QF: name = g_strdup("QF"); break;
case REG_GE: name = g_strdup("GE"); break;
default: name = g_strdup_printf("R%u", (unsigned int)reg); break;
}
}
return build_load_store_reg_op(name, ls, &val, sizeof(val));
}

OperandInfo * load_store_reg64(uint32_t reg, uint64_t val, int ls) {
return build_load_store_reg_op(g_strdup_printf("D%u", (unsigned int)reg), ls, &val, sizeof(val));
OperandInfo *load_store_reg64(uint32_t reg, uint64_t val, int ls) {
char *name;
if (reg >= REG64_D0) {
name = g_strdup_printf("D%u", (unsigned int)reg - REG64_D0);
} else {
name = g_strdup_printf("R%u", (unsigned int)reg);
}
return build_load_store_reg_op(name, ls, &val, sizeof(val));
}

void HELPER(log_store_cpsr)(CPUARMState *env)
static void trace_cpsr(CPUARMState *env, uint32_t mask, int ls)
{
OperandInfo *oi;
uint32_t val = cpsr_read(env);

oi = load_store_reg(REG_NF, (val >> 31) & 0x1, 1);
qemu_trace_add_operand(oi, 0x2);

oi = load_store_reg(REG_ZF, (val >> 30) & 0x1, 1);
qemu_trace_add_operand(oi, 0x2);

oi = load_store_reg(REG_CF, (val >> 29) & 0x1, 1);
qemu_trace_add_operand(oi, 0x2);

oi = load_store_reg(REG_VF, (val >> 28) & 0x1, 1);
qemu_trace_add_operand(oi, 0x2);

oi = load_store_reg(REG_QF, (val >> 27) & 0x1, 1);
qemu_trace_add_operand(oi, 0x2);

oi = load_store_reg(REG_GE, (val >> 16) & 0xF, 1);
qemu_trace_add_operand(oi, 0x2);
int inout = ls ? 2 : 1;
if (mask & TRACE_CPSR_NF) {
qemu_trace_add_operand(load_store_reg(REG_NF, (val >> 31) & 0x1, ls), inout);
}
if (mask & TRACE_CPSR_ZF) {
qemu_trace_add_operand(load_store_reg(REG_ZF, (val >> 30) & 0x1, ls), inout);
}
if (mask & TRACE_CPSR_CF) {
qemu_trace_add_operand(load_store_reg(REG_CF, (val >> 29) & 0x1, ls), inout);
}
if (mask & TRACE_CPSR_VF) {
qemu_trace_add_operand(load_store_reg(REG_VF, (val >> 28) & 0x1, ls), inout);
}
if (mask & TRACE_CPSR_QF) {
qemu_trace_add_operand(load_store_reg(REG_QF, (val >> 27) & 0x1, ls), inout);
}
if (mask & TRACE_CPSR_GE) {
qemu_trace_add_operand(load_store_reg(REG_GE, (val >> 16) & 0xF, ls), inout);
}
}

void HELPER(log_read_cpsr)(CPUARMState *env)
void HELPER(trace_store_cpsr)(CPUARMState *env, uint32_t mask)
{
OperandInfo *oi;
uint32_t val = cpsr_read(env);

oi = load_store_reg(REG_NF, (val >> 31) & 0x1, 0);
qemu_trace_add_operand(oi, 0x1);

oi = load_store_reg(REG_ZF, (val >> 30) & 0x1, 0);
qemu_trace_add_operand(oi, 0x1);

oi = load_store_reg(REG_CF, (val >> 29) & 0x1, 0);
qemu_trace_add_operand(oi, 0x1);

oi = load_store_reg(REG_VF, (val >> 28) & 0x1, 0);
qemu_trace_add_operand(oi, 0x1);

oi = load_store_reg(REG_QF, (val >> 27) & 0x1, 0);
qemu_trace_add_operand(oi, 0x1);
trace_cpsr(env, mask, 1);
}

oi = load_store_reg(REG_GE, (val >> 16) & 0xF, 0);
qemu_trace_add_operand(oi, 0x1);
void HELPER(trace_read_cpsr)(CPUARMState *env, uint32_t mask)
{
trace_cpsr(env, mask, 0);
}

void HELPER(trace_load_reg)(uint32_t reg, uint32_t val)
Expand All @@ -172,95 +152,100 @@ void HELPER(trace_store_reg)(uint32_t reg, uint32_t val)

void HELPER(trace_load_reg64)(uint32_t reg, uint64_t val)
{
qemu_log("This 64-bit register (d%d) was read. Value 0x%llx\n", reg, (unsigned long long)val);
qemu_log("This 64-bit register (%d) was read. Value 0x%llx\n", reg, (unsigned long long)val);
OperandInfo *oi = load_store_reg64(reg, val, 0);
qemu_trace_add_operand(oi, 0x1);
}

void HELPER(trace_store_reg64)(uint32_t reg, uint64_t val)
{
qemu_log("This 64-bit register (d%d) was written. Value: 0x%llx\n", reg, (unsigned long long)val);
qemu_log("This 64-bit register (%d) was written. Value: 0x%llx\n", reg, (unsigned long long)val);
OperandInfo *oi = load_store_reg64(reg, val, 1);
qemu_trace_add_operand(oi, 0x2);
}

void HELPER(trace_ld)(CPUARMState *env, uint32_t val, uint32_t addr, uint32_t opc)
{
int len;
qemu_log("This was a read 0x%x addr:0x%x value:0x%x\n", env->regs[15], addr, val);
switch (opc & MO_SIZE) {
case MO_8:
len = 1;
break;
case MO_16:
len = 2;
break;
case MO_32:
len = 4;
break;
default:
qemu_log("Do not reach\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 0, &val, len);
size_t sz = memop_size(opc);
if (!sz || sz > 4) {
qemu_log("Invalid memop\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 0, &val, sz);
qemu_trace_add_operand(oi, 0x1);
}

void HELPER(trace_st)(CPUARMState *env, uint32_t val, uint32_t addr, uint32_t opc)
{
int len;
qemu_log("This was a store 0x%x addr:0x%x value:0x%x\n", env->regs[15], addr, val);

switch (opc & MO_SIZE) {
case MO_8:
len = 1;
break;
case MO_16:
len = 2;
break;
case MO_32:
len = 4;
break;
default:
qemu_log("Do not reach\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 1, &val, len);
size_t sz = memop_size(opc);
if (!sz || sz > 4) {
qemu_log("Invalid memop\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 1, &val, sz);
qemu_trace_add_operand(oi, 0x2);
}

void HELPER(trace_ld64)(CPUARMState *env, uint64_t val, uint32_t addr, uint32_t opc)
{
int len;
qemu_log("This was a 64-bit read 0x%x addr:0x%x value:0x%llx\n", env->regs[15], addr, (unsigned long long)val);
switch (opc & MO_SIZE) {
case MO_64:
len = 8;
break;
default:
qemu_log("Do not reach\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 0, &val, len);
size_t sz = memop_size(opc);
if (!sz || sz > 8) {
qemu_log("Invalid memop\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 0, &val, sz);
qemu_trace_add_operand(oi, 0x1);
}

void HELPER(trace_st64)(CPUARMState *env, uint64_t val, uint32_t addr, uint32_t opc)
{
int len;
qemu_log("This was a 64-bit store 0x%x addr:0x%x value:0x%llx\n", env->regs[15], addr, (unsigned long long)val);
switch (opc & MO_SIZE) {
case MO_64:
len = 8;
break;
default:
qemu_log("Do not reach\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 1, &val, len);
size_t sz = memop_size(opc);
if (!sz || sz > 8) {
qemu_log("Invalid memop\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 1, &val, sz);
qemu_trace_add_operand(oi, 0x2);
}

void HELPER(trace_mode)(void *mode) {
qemu_trace_set_mode(mode);
}

#ifdef TARGET_AARCH64
void HELPER(trace_newframe_64)(uint64_t pc) {
qemu_trace_newframe(pc, 0);
}

void HELPER(trace_endframe_64)(CPUARMState *env, uint64_t old_pc) {
qemu_trace_endframe(env, old_pc, 4);
}

void HELPER(trace_ld64_64)(CPUARMState *env, uint64_t val, uint64_t addr, uint32_t opc)
{
qemu_log("This was a 64-bit read 0x%x addr:0x%llx value:0x%llx\n", env->regs[15], (unsigned long long)addr, (unsigned long long)val);
size_t sz = memop_size(opc);
if (!sz || sz > 8) {
qemu_log("Invalid memop\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 0, &val, sz);
qemu_trace_add_operand(oi, 0x1);
}

void HELPER(trace_st64_64)(CPUARMState *env, uint64_t val, uint64_t addr, uint32_t opc)
{
qemu_log("This was a 64-bit store 0x%x addr:0x%llx value:0x%llx\n", env->regs[15], (unsigned long long)addr, (unsigned long long)val);
size_t sz = memop_size(opc);
if (!sz || sz > 8) {
qemu_log("Invalid memop\n");
return;
}
OperandInfo *oi = load_store_mem(addr, 1, &val, sz);
qemu_trace_add_operand(oi, 0x2);
}
#endif
Loading

0 comments on commit 03d66a8

Please sign in to comment.