Files
SameBoy/Core/trace.cpp

181 lines
4.8 KiB
C++

#ifdef ENABLE_BAP_FRAMES
#include <trace.container.hpp>
struct GB_trace_state_t
{
SerializedTrace::TraceContainerWriter *writer;
bool frame_started = false;
uint16_t pc;
uint8_t op[4];
size_t op_size;
operand_value_list *pre;
operand_value_list *post;
};
// If we would include gb.h, the GB_gameboy_t would have a different layout than in C for some reason.
// We work around it by only calling only functions.
typedef struct GB_gameboy_s GB_gameboy_t;
extern "C" GB_trace_state_t **GB_trace_member(GB_gameboy_t *gb);
extern "C" void GB_log(GB_gameboy_t *gb, const char *fmt, ...);
extern "C" void GB_get_rom_title(GB_gameboy_t *gb, char *title);
extern "C" void GB_trace_open(GB_gameboy_t *gb, const char *filename)
{
GB_trace_state_t **tp = GB_trace_member(gb);
if (*tp) {
GB_log(gb, "Error: Trace was already opened.\n");
return;
}
tracer *trac = new tracer();
trac->set_name("sameboy");
trac->set_version("");
target *tgt = new target();
char title[17];
GB_get_rom_title(gb, title);
tgt->set_path(title);
tgt->set_md5sum("");
fstats *fst = new fstats();
fst->set_size(0);
fst->set_atime(0.0);
fst->set_mtime(0.0);
fst->set_ctime(0.0);
meta_frame meta;
meta.set_allocated_tracer(trac);
meta.set_allocated_target(tgt);
meta.set_allocated_fstats(fst);
meta.set_user("");
meta.set_host("");
meta.set_time(0.0);
try {
auto writer = new SerializedTrace::TraceContainerWriter(filename, meta, frame_arch_sm83, 0);
GB_trace_state_t *t = new GB_trace_state_t;
t->writer = writer;
*tp = t;
} catch (std::exception e) {
GB_log(gb, "Error: Trace open failed: %s\n", e.what());
}
}
extern "C" void GB_trace_close(GB_gameboy_t *gb)
{
GB_trace_state_t **tp = GB_trace_member(gb);
auto t = *tp;
if (!t) {
GB_log(gb, "Error: No trace was opened.\n");
return;
}
if (t->frame_started) {
GB_log(gb, "Warning: closing trace with unfinished frame.\n");
}
t->writer->finish();
delete t->writer;
delete t;
*tp = NULL;
}
extern "C" void GB_trace_frame_begin(GB_gameboy_t *gb, uint16_t pc, uint8_t *op, size_t sz)
{
auto t = *GB_trace_member(gb);
if (t->frame_started) {
GB_log(gb, "Frame already started!\n");
return;
}
t->pc = pc;
memcpy(t->op, op, sz);
t->op_size = sz;
t->pre = new operand_value_list();
t->post = new operand_value_list();
t->frame_started = true;
}
extern "C" void GB_trace_frame_end(GB_gameboy_t *gb)
{
auto t = *GB_trace_member(gb);
if (!t->frame_started) {
GB_log(gb, "No frame started!\n");
return;
}
std_frame *sf = new std_frame();
sf->set_address(t->pc);
sf->set_thread_id(0);
sf->set_rawbytes(std::string((const char *)t->op, t->op_size));
sf->set_allocated_operand_pre_list(t->pre);
sf->set_allocated_operand_post_list(t->post);
frame f;
f.set_allocated_std_frame(sf);
t->writer->add(f);
t->frame_started = false;
}
extern "C" void GB_trace_push_reg(GB_gameboy_t *gb, bool post, const char *name, uint16_t v, size_t bits)
{
auto t = *GB_trace_member(gb);
if (!t->frame_started) {
GB_log(gb, "No frame started!\n");
return;
}
auto l = post ? t->post : t->pre;
reg_operand *ro = new reg_operand();
ro->set_name(name);
operand_info_specific *s = new operand_info_specific();
s->set_allocated_reg_operand(ro);
operand_usage *u = new operand_usage();
u->set_read(!post);
u->set_written(post);
u->set_index(false);
u->set_base(false);
taint_info *ti = new taint_info();
operand_info *i = l->add_elem();
i->set_allocated_operand_info_specific(s);
i->set_bit_length((int32_t)bits);
i->set_allocated_operand_usage(u);
i->set_allocated_taint_info(ti);
uint8_t va[2] = { (uint8_t)v, (uint8_t)(v >> 8) };
i->set_value(std::string((const char *)va, (bits + 7) / 8));
}
extern "C" void GB_trace_push_mem(GB_gameboy_t *gb, bool post, uint16_t addr, uint8_t val)
{
auto t = *GB_trace_member(gb);
if (!t->frame_started) {
GB_log(gb, "No frame started!\n");
return;
}
auto l = post ? t->post : t->pre;
mem_operand *mo = new mem_operand();
mo->set_address(addr);
operand_info_specific *s = new operand_info_specific();
s->set_allocated_mem_operand(mo);
operand_usage *u = new operand_usage();
u->set_read(!post);
u->set_written(post);
u->set_index(false);
u->set_base(false);
taint_info *ti = new taint_info();
operand_info *i = l->add_elem();
i->set_allocated_operand_info_specific(s);
i->set_bit_length(8);
i->set_allocated_operand_usage(u);
i->set_allocated_taint_info(ti);
i->set_value(std::string((const char *)&val, 1));
}
#endif