// File: /workspace/github_c_makefile_star2_O3/melynx[P]peekaboo/libpeekaboo/libpeekaboo.c
// Function: load_trace
void load_trace(char *dir_path, peekaboo_trace_t *trace_ptr)
{
	char path[MAX_PATH];

	// Load metadata first
	snprintf(path, MAX_PATH, "%s/%s", dir_path, "metafile");
	trace_ptr->metafile = fopen(path, "rb");
	if (trace_ptr->metafile == NULL) PEEKABOO_DIE("libpeekaboo: Unable to load %s\n", path);

	// Creates the internal data-structure to store the
	// meta-information about the loaded trace
	trace_ptr->internal = malloc(sizeof(peekaboo_internal_t));
	memset(trace_ptr->internal, 0, sizeof(peekaboo_internal_t));

	// Setup the information
	metadata_hdr_t meta;
	size_t fread_bytes = fread(&meta, sizeof(metadata_hdr_t), 1, trace_ptr->metafile);
	trace_ptr->internal->arch = meta.arch;
	trace_ptr->internal->version = meta.version;
	fprintf(stderr, "Trace's libpeekaboo version: %d\n", meta.version);
	fclose(trace_ptr->metafile);

	if (trace_ptr->internal->version >= 4)
	{
		// New trace format that can customize which registers to store
		if (trace_ptr->internal->arch == ARCH_AMD64)
		{
			trace_ptr->internal->storage_options.amd64.has_simd = meta.storage_options.amd64.has_simd;
			trace_ptr->internal->storage_options.amd64.has_fxsave = meta.storage_options.amd64.has_fxsave;
			fprintf(stderr, "Stored register: GPRs ");
			if (trace_ptr->internal->storage_options.amd64.has_simd) fprintf(stderr, "SIMD ");
			if (trace_ptr->internal->storage_options.amd64.has_fxsave) fprintf(stderr, "FXSAVE ");
			fprintf(stderr, "\n");
		}
	}
	else
	{
		// Trace version lower than 003, stores everything
		trace_ptr->internal->storage_options.amd64.has_simd = 1;
		trace_ptr->internal->storage_options.amd64.has_fxsave = 1;
	}

	switch (meta.arch)
	{
		case ARCH_AMD64:
			trace_ptr->internal->ptr_size = 8;
			trace_ptr->internal->regfile_size = sizeof(regfile_amd64_t);
			break;
		case ARCH_AARCH64:
			trace_ptr->internal->ptr_size = 8;
			trace_ptr->internal->regfile_size = sizeof(regfile_aarch64_t);
			break;
		case ARCH_X86:
			trace_ptr->internal->ptr_size = 4;
			trace_ptr->internal->regfile_size = sizeof(regfile_x86_t);
			break;
		default:
			trace_ptr->internal->ptr_size = 0;
			trace_ptr->internal->regfile_size = 0;
			break;
	}

	// Load bytes_map based on the version
	if (meta.version > 1)
		snprintf(path, MAX_PATH, "%s/../%s", dir_path, "insn.bytemap");
	else
		// Legacy trace format in Verion 1 which does not have separate folders for different threads.
		snprintf(path, MAX_PATH, "%s/%s", dir_path, "insn.bytemap");
	trace_ptr->bytes_map = fopen(path, "rb");
	if (trace_ptr->bytes_map == NULL) PEEKABOO_DIE("libpeekaboo: Unable to load bytes_map\n");

	// Load insn.trace, regfile, memfile, memrefs.
	snprintf(path, MAX_PATH, "%s/%s", dir_path, "insn.trace");
	trace_ptr->insn_trace = fopen(path, "rb");
	if (trace_ptr->insn_trace == NULL) PEEKABOO_DIE("libpeekaboo: Unable to load %s\n", path);
	snprintf(path, MAX_PATH, "%s/%s", dir_path, "regfile");
	trace_ptr->regfile = fopen(path, "rb");
	if (trace_ptr->regfile == NULL) PEEKABOO_DIE("libpeekaboo: Unable to load %s\n", path);
	snprintf(path, MAX_PATH, "%s/%s", dir_path, "memfile");
	trace_ptr->memfile = fopen(path, "rb");
	if (trace_ptr->memfile == NULL) PEEKABOO_DIE("libpeekaboo: Unable to load %s\n", path);
	snprintf(path, MAX_PATH, "%s/%s", dir_path, "memrefs");
	trace_ptr->memrefs = fopen(path, "rb");
	if (trace_ptr->memrefs == NULL) PEEKABOO_DIE("libpeekaboo: Unable to load %s\n", path);

	// Init for internal structure
	size_t trace_size = 0;
	size_t ptr_size = trace_ptr->internal->ptr_size;
	fseek(trace_ptr->insn_trace, 0, SEEK_END);
	trace_size = ftell(trace_ptr->insn_trace);
	rewind(trace_ptr->insn_trace);
	trace_ptr->internal->num_insns = trace_size/ptr_size;

	// loads the rawbytes map for the trace
	load_bytes_map(trace_ptr);

	// load memrefs_offsets. Create if not exist 
	load_memrefs_offsets(dir_path, trace_ptr);

	// All good. Ready to go~!
	return ;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x20dc(%rip), %r15      # 0x5fca
leaq 0x2048(%rip), %r8       # 0x5f3d
leaq 0x10(%rsp), %r12
movl $0x100, %esi            # imm = 0x100
movq %r12, %rdi
movq %r15, %rdx
movq %r14, %rcx
xorl %eax, %eax
callq 0x3150
leaq 0x21af(%rip), %rsi      # 0x60c5
movq %r12, %rdi
callq 0x3260
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x41be
movq %rax, %r13
movl $0x1, %edi
movl $0x68, %esi
callq 0x31a0
leaq 0x38(%rbx), %r12
movq %rax, 0x38(%rbx)
movq %rsp, %rbp
movl $0x10, %esi
movl $0x1, %edx
movq %rbp, %rdi
movq %r13, %rcx
callq 0x30d0
movl (%rbp), %r13d
movq 0x38(%rbx), %rax
movl %r13d, (%rax)
movl 0x4(%rbp), %ebp
movl %ebp, 0x58(%rax)
movq 0x607b(%rip), %rax      # 0x9ff0
movq (%rax), %rdi
leaq 0x2169(%rip), %rsi      # 0x60e8
movl %ebp, %edx
xorl %eax, %eax
callq 0x31b0
movq 0x28(%rbx), %rdi
callq 0x30f0
movq 0x38(%rbx), %rsi
cmpl $0x4, 0x58(%rsi)
jb 0x3fad
cmpl $0x3, (%rsi)
jne 0x3fbc
movq %rsp, %rdi
movq %r12, %rdx
callq 0x33b8
jmp 0x3fbc
movl $0x1, %eax
movl %eax, 0x60(%rsi)
movq (%r12), %rcx
movl %eax, 0x64(%rcx)
movq (%r12), %rax
cmpl $0x1, %r13d
je 0x3ff6
cmpl $0x2, %r13d
je 0x3fe4
cmpl $0x3, %r13d
jne 0x4008
movq $0x8, 0x8(%rax)
movq $0x490, 0x10(%rax)      # imm = 0x490
jmp 0x4012
movq $0x4, 0x8(%rax)
movq $0x20, 0x10(%rax)
jmp 0x4012
movq $0x8, 0x8(%rax)
movq $0x318, 0x10(%rax)      # imm = 0x318
jmp 0x4012
addq $0x8, %rax
xorps %xmm0, %xmm0
movups %xmm0, (%rax)
cmpl $0x2, %ebp
leaq 0x2112(%rip), %rax      # 0x612e
cmovaeq %rax, %r15
leaq 0x2110(%rip), %r8       # 0x6137
leaq 0x10(%rsp), %r12
movl $0x100, %esi            # imm = 0x100
movq %r12, %rdi
movq %r15, %rdx
movq %r14, %rcx
xorl %eax, %eax
callq 0x3150
leaq 0x207d(%rip), %rsi      # 0x60c5
movq %r12, %rdi
callq 0x3260
movq %rax, 0x8(%rbx)
testq %rax, %rax
je 0x41c8
leaq 0x1f66(%rip), %rdx      # 0x5fca
leaq 0x1eaf(%rip), %r8       # 0x5f1a
leaq 0x10(%rsp), %r15
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rcx
xorl %eax, %eax
callq 0x3150
leaq 0x203c(%rip), %rsi      # 0x60c5
movq %r15, %rdi
callq 0x3260
movq %rax, (%rbx)
testq %rax, %rax
je 0x41cd
leaq 0x1f26(%rip), %rdx      # 0x5fca
leaq 0x1e7a(%rip), %r8       # 0x5f25
leaq 0x10(%rsp), %r15
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rcx
xorl %eax, %eax
callq 0x3150
leaq 0x1ffc(%rip), %rsi      # 0x60c5
movq %r15, %rdi
callq 0x3260
movq %rax, 0x10(%rbx)
testq %rax, %rax
je 0x41d7
leaq 0x1ee5(%rip), %rdx      # 0x5fca
leaq 0x1e41(%rip), %r8       # 0x5f2d
leaq 0x10(%rsp), %r15
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rcx
xorl %eax, %eax
callq 0x3150
leaq 0x1fbb(%rip), %rsi      # 0x60c5
movq %r15, %rdi
callq 0x3260
movq %rax, 0x20(%rbx)
testq %rax, %rax
je 0x41e1
leaq 0x1ea4(%rip), %rdx      # 0x5fca
leaq 0x1e08(%rip), %r8       # 0x5f35
leaq 0x10(%rsp), %r15
movl $0x100, %esi            # imm = 0x100
movq %r15, %rdi
movq %r14, %rcx
xorl %eax, %eax
callq 0x3150
leaq 0x1f7a(%rip), %rsi      # 0x60c5
movq %r15, %rdi
callq 0x3260
movq %rax, 0x18(%rbx)
testq %rax, %rax
je 0x41eb
movq (%rbx), %rdi
movq 0x38(%rbx), %rax
movq 0x8(%rax), %r12
xorl %esi, %esi
movl $0x2, %edx
callq 0x3230
movq (%rbx), %rdi
callq 0x31c0
movq %rax, %r15
movq (%rbx), %rdi
callq 0x3140
movq %r15, %rax
xorl %edx, %edx
divq %r12
movq 0x38(%rbx), %rcx
movq %rax, 0x28(%rcx)
movq %rbx, %rdi
callq 0x3250
movq %r14, %rdi
movq %rbx, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x31d0
leaq 0x10(%rsp), %rdi
callq 0x34f1
callq 0x34cc
leaq 0x10(%rsp), %rdi
callq 0x34a8
leaq 0x10(%rsp), %rdi
callq 0x3484
leaq 0x10(%rsp), %rdi
callq 0x3460
leaq 0x10(%rsp), %rdi
callq 0x343c