// File: /workspace/github_c_makefile_star2_O3/melynx[P]peekaboo/read_trace.c
// Function: main
int main(int argc, char *argv[])
{
    // Init capstone
#ifdef ASM_CAPSTONE
    if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handler) != CS_ERR_OK) PEEKABOO_DIE("Capstone init error.");
#endif
    write_bytes = 0;
    read_bytes = 0;
    int loop_starts = 1;                    // Default is 1 for printing from beginning
    int loop_ends = 0;                      // Default is 0 for printing till the end
    char *pattern_file_path;                // Path to the pattern file for pattern search mode
    bool is_search = false;                 // Pattern search mode
    bool print_syscall_only = false;        // Strace mode 
    uint64_t target_addr = (uint64_t) -1;   // Target memory address for memory access search mode
    uint32_t target_addr_size = 1;          // Buffer size for memory access search mode. By default only check 1 byte
    bool target_addr_size_hex = false;      // Does user type-in buffer size in hex? For memory access search mode
    char *comma_pos, *size_ptr;             // Temp pointers for arg parsing. For memory access search mode
    uint64_t printed_instr_num = 0;         // Counter for how many instr have been printed for non-pattern-search modes

    // Argument parsing
    int opt;
    while ((opt = getopt(argc, argv, "hrms:p:e:a:y")) != -1) {
        switch (opt) {
        case 'r':
            print_register = true;
            break;
        case 'm':
            print_memory = true;
            break;
        case 'p':
            pattern_file_path = optarg;
            is_search = true;
            break;
        case 's':
            loop_starts = atoi(optarg);
            if (loop_starts == 0) PEEKABOO_DIE("Starting point could not be 0. Traces always start at 1.\n");
            break;
        case 'e':
            loop_ends = atoi(optarg);
            if (loop_ends <= 0) PEEKABOO_DIE("End point must be greater than 0\n");
            break;
        case 'a':
            comma_pos = strrchr(optarg, ',');
            if (optarg[0] == '0' && optarg[1] == 'x')
                target_addr = strtol(optarg+2, NULL, 16);
            else
                target_addr = strtol(optarg, NULL, 16);
            if (comma_pos != NULL)
            {
                size_ptr = comma_pos + 1;
                if (size_ptr[0] == '0' && size_ptr[1] == 'x')
                {
                    target_addr_size = strtol(size_ptr+2, NULL, 16);
                    target_addr_size_hex = true;
                }
                else
                {
                    target_addr_size = strtol(size_ptr, NULL, 10);
                    target_addr_size_hex = false;
                }
            }
            break;
        case 'y':
            print_syscall_only = true;
            break;
        case 'h':
            print_usage(argv[0]);
            exit(EXIT_FAILURE);
            break;
        }
    }
    // Check mandatory argument, path to a trace folder
    if (optind >= argc) 
    {
        print_usage(argv[0]);
        PEEKABOO_DIE("\nMissing argument: Trace path at the end expected.\n");
    }

    // Print current libpeekaboo version
    fprintf(stderr, "libpeekaboo version: %d\n", LIBPEEKABOO_VER);

    // Print info for memory access search
    if (target_addr != (uint64_t) -1)
    {
        if (target_addr_size > 1)  
        {
            printf("Search for memory access to buffer at 0x%lx with size of ",target_addr);
            if (target_addr_size_hex) // Buffer size is taken in hex or dec
                printf("0x%x bytes.\n", target_addr_size);
            else
                printf("%u bytes.\n", target_addr_size);
        }
        else
        {
            printf("Search for memory access @0x%lx.\n", target_addr);
        }
    }

    // Load trace
    char *trace_path = argv[argc - 1];
    peekaboo_trace_t *peekaboo_trace_ptr = malloc(sizeof(peekaboo_trace_t));
    if (peekaboo_trace_ptr == NULL) PEEKABOO_DIE("Fail to malloc trace structure.");
    load_trace(trace_path, peekaboo_trace_ptr);

    // Get and print the length of the trace
    const size_t num_insn = get_num_insn(peekaboo_trace_ptr);
    digits = (uint8_t) log10(num_insn) + 2;

    // Load and Print search pattern
    cache_linked_list_t pattern;
    pattern.length = 0;
    pattern.head = NULL;
    pattern.tail = NULL;
    if (is_search) load_pattern(&pattern, pattern_file_path);
    if (pattern.length) print_pattern(&pattern);

    // Prepare buffer for pattern searching
    cache_linked_list_t instr_buffer;
    instr_buffer.length = 0;
    instr_buffer.head = NULL;
    instr_buffer.tail = NULL;
    uint64_t num_found_block = 0;
    matched_list_node_t *matched_list_header = NULL;

    // We print instructions sequentially. 
    // Please note the first instruction's index is 1, instead of 0.
    const size_t _loop_ends = (loop_ends) ? loop_ends : num_insn;
    const size_t _loop_starts = (loop_starts < 0) ? (_loop_ends + loop_starts + 1) : loop_starts;
    printf("Range: from %lu to %lu (%lu in total)\n", _loop_starts, _loop_ends, num_insn);
    for (size_t insn_idx=_loop_starts; insn_idx<=_loop_ends; insn_idx++)
    {
        // Get instruction ptr by instruction index
        peekaboo_insn_t *insn = get_peekaboo_insn(insn_idx, peekaboo_trace_ptr);
        
        // strace mode
        if (print_syscall_only)
        {
            if (insn->size == 2 && insn->rawbytes[0]=='\x0f' && insn->rawbytes[1]=='\x05')
            {
                print_peekaboo_insn(insn, peekaboo_trace_ptr, insn_idx, false, true);
                printed_instr_num++;
            }
            free_peekaboo_insn(insn);
            continue;
        }

        // Pattern search
        if (pattern.length)
        {
            update_raw_byte_buffer(&instr_buffer, insn->rawbytes, insn->size, pattern.length);
            uint32_t matched_bytes_num = is_buffer_matched(&instr_buffer, &pattern);
            if (matched_bytes_num)
            {
                num_found_block ++;
                print_next = PRINT_NEXT;
                if (num_found_block) printf("\n");
                printf("[Target block %lu] ends at [%lu]0x%"PRIx64":\n", num_found_block, insn_idx, insn->addr);
                print_back(matched_bytes_num, peekaboo_trace_ptr, insn_idx);
                append2macthed_list(&matched_list_header, insn->addr);
                free_peekaboo_insn(insn);
                continue;
            }
        }

        // Call print_filter() to decide what should be printed
        if (!print_filter(insn, insn_idx, num_insn, is_search, target_addr, target_addr_size))
        {   
            // We are NOT going to print this instruction. Free and skip!
            free_peekaboo_insn(insn);
            continue;
        }
        else
        {   
            // We are going to print this instruction.
            printed_instr_num++;
        }
        

        // Body of print
        print_peekaboo_insn(insn, peekaboo_trace_ptr, insn_idx, false, false);

        // Free instruction ptr
        free_peekaboo_insn(insn);
    }

    
    if (pattern.length)
    {   
        // Print pattern search summary and free linked list
        printf("%lu code snippet(s) matched with the given pattern", num_found_block);
        if (num_found_block)
        {
            printf(":\n");
            matched_list_node_t *node = matched_list_header;
            while (node != NULL)
            {
                printf("  Found pattern at 0x%lx for %ld time(s)\n", node->addr, node->cnt);
                matched_list_node_t *this_node = node;
                node = node->succ;
                free(this_node);
            }
        }
    }
    else
    {   
        // Print a total info for non-pattern modes
        printf("End of printing. Totol printed instructions: %lu.\n", printed_instr_num);
    }
    

#ifdef ASM_CAPSTONE
	cs_close(&capstone_handler);
#endif
    if (pattern.length)
    {
        free_dulinked_list(&pattern);
        free_dulinked_list(&instr_buffer);
    }
    free_peekaboo_trace(peekaboo_trace_ptr);
    
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rsi, %r15
movl %edi, %r14d
xorl %eax, %eax
movq %rax, 0x7d45(%rip)      # 0xc148
movq $0x0, (%rsp)
movq %rax, 0x7d3e(%rip)      # 0xc150
movq $-0x1, %rbp
movl $0x1, %eax
movq %rax, 0x10(%rsp)
leaq 0x213d(%rip), %rbx      # 0x6567
leaq 0x1bff(%rip), %r12      # 0x6030
movq $0x0, 0x30(%rsp)
movq $0x0, 0x18(%rsp)
movl $0x0, 0x8(%rsp)
movl $0x1, 0x28(%rsp)
movl %r14d, %edi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x3200
cmpl $0x64, %eax
jle 0x4497
leal -0x65(%rax), %ecx
cmpl $0xe, %ecx
ja 0x4522
movslq (%r12,%rcx,4), %rax
addq %r12, %rax
jmpq *%rax
movq 0x7b56(%rip), %rax      # 0xbfd8
movq (%rax), %rdi
callq 0x3210
movl %eax, 0x8(%rsp)
testl %eax, %eax
jg 0x4453
jmp 0x49b0
cmpl $0x61, %eax
jne 0x458a
movq 0x7b31(%rip), %rax      # 0xbfd8
movq (%rax), %rbp
movq %rbp, %rdi
movl $0x2c, %esi
callq 0x3100
movq %rax, %r13
cmpb $0x30, (%rbp)
jne 0x44ce
xorl %eax, %eax
cmpb $0x78, 0x1(%rbp)
sete %al
leaq (%rbp,%rax,2), %rbp
movq %rbp, %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x3190
movq %rax, %rbp
testq %r13, %r13
je 0x4453
cmpb $0x30, 0x1(%r13)
jne 0x4595
cmpb $0x78, 0x2(%r13)
jne 0x4595
addq $0x3, %r13
movq %r13, %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x3190
movq %rax, 0x10(%rsp)
movb $0x1, %al
movq %rax, (%rsp)
jmp 0x4453
cmpl $0x79, %eax
jne 0x4453
movb $0x1, %al
movq %rax, 0x30(%rsp)
jmp 0x4453
movq 0x7a9a(%rip), %rax      # 0xbfd8
movq (%rax), %rax
movq %rax, 0x20(%rsp)
movb $0x1, %al
movq %rax, 0x18(%rsp)
jmp 0x4453
movq 0x7a7f(%rip), %rax      # 0xbfd8
movq (%rax), %rdi
callq 0x3210
movl %eax, 0x28(%rsp)
testl %eax, %eax
jne 0x4453
jmp 0x49b5
movb $0x1, 0x7bbf(%rip)      # 0xc138
jmp 0x4453
movb $0x1, 0x7bb4(%rip)      # 0xc139
jmp 0x4453
cmpl $-0x1, %eax
jne 0x4453
jmp 0x45b9
incq %r13
movq $0x0, (%rsp)
movq %r13, %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x3190
movq %rax, 0x10(%rsp)
jmp 0x4453
movq 0x7a10(%rip), %rax      # 0xbfd0
cmpl %r14d, (%rax)
jge 0x49c2
movq 0x7a28(%rip), %rax      # 0xbff8
movq (%rax), %rdi
leaq 0x30ab(%rip), %rsi      # 0x7685
movl $0x4, %edx
xorl %eax, %eax
callq 0x3160
cmpq $-0x1, %rbp
movq 0x18(%rsp), %r13
je 0x463e
cmpl $0x2, 0x10(%rsp)
jb 0x4618
leaq 0x2005(%rip), %rdi      # 0x6604
movq %rbp, %rsi
xorl %eax, %eax
callq 0x30d0
testb $0x1, (%rsp)
je 0x462b
leaq 0x2028(%rip), %rdi      # 0x663e
jmp 0x4632
leaq 0x2037(%rip), %rdi      # 0x6656
movq %rbp, %rsi
xorl %eax, %eax
callq 0x30d0
jmp 0x463e
leaq 0x2019(%rip), %rdi      # 0x664b
movq 0x10(%rsp), %rsi
xorl %eax, %eax
callq 0x30d0
movslq %r14d, %rax
movq -0x8(%r15,%rax,8), %rbx
movl $0x40, %edi
callq 0x31b0
testq %rax, %rax
movq 0x20(%rsp), %r14
je 0x49ca
movq %rax, %r15
movq %rbx, %rdi
movq %rax, %rsi
callq 0x5148
movq %r15, %rdi
callq 0x4e13
movq %rax, %r12
movq %rax, %xmm1
punpckldq 0x198c(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x1994(%rip), %xmm1     # 0x6020
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
callq 0x3150
cvttsd2si %xmm0, %eax
addb $0x2, %al
movb %al, 0x7a97(%rip)       # 0xc140
xorpd %xmm0, %xmm0
movapd %xmm0, 0x40(%rsp)
movq $0x0, 0x50(%rsp)
movb $0x1, %al
movl %eax, (%rsp)
movq %r13, 0x18(%rsp)
testb $0x1, %r13b
je 0x46f8
leaq 0x40(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4107
movq 0x10(%rbx), %r13
testq %r13, %r13
je 0x46fd
leaq 0x40(%rsp), %rdi
callq 0x4274
movl $0x0, (%rsp)
jmp 0x4700
xorl %r13d, %r13d
jmp 0x4704
xorl %r13d, %r13d
xorpd %xmm0, %xmm0
movapd %xmm0, 0x60(%rsp)
xorl %eax, %eax
movq %rax, 0x70(%rsp)
movq %rax, 0x38(%rsp)
movl 0x8(%rsp), %eax
testl %eax, %eax
movl %eax, %ebx
cmoveq %r12, %rbx
movl 0x28(%rsp), %eax
testl %eax, %eax
cltq
leaq 0x1(%rax,%rbx), %rdx
movl %eax, %r14d
cmovsq %rdx, %r14
leaq 0x1f5b(%rip), %rdi      # 0x6698
movq %r14, %rsi
movq %rbx, %rdx
movq %r12, %rcx
xorl %eax, %eax
callq 0x30d0
cmpq %rbx, %r14
jbe 0x4763
cmpb $0x0, (%rsp)
je 0x493f
xorl %esi, %esi
jmp 0x48cd
movq %rbp, 0x28(%rsp)
movzbl 0x18(%rsp), %eax
andl $0x1, %eax
movl %eax, 0x18(%rsp)
movq $0x0, 0x20(%rsp)
xorl %eax, %eax
movq %rax, 0x8(%rsp)
movq %r14, %rdi
movq %r15, %rsi
callq 0x551a
movq %rax, %r12
testb $0x1, 0x30(%rsp)
je 0x47da
cmpq $0x2, 0x8(%r12)
jne 0x483f
cmpb $0xf, 0x10(%r12)
jne 0x483f
cmpb $0x5, 0x11(%r12)
jne 0x483f
movq %r12, %rdi
movq %r15, %rsi
movq %r14, %rdx
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x3c72
incq 0x8(%rsp)
jmp 0x483f
cmpb $0x0, (%rsp)
jne 0x480d
movq %r12, %rsi
addq $0x10, %rsi
movl 0x8(%r12), %edx
leaq 0x60(%rsp), %rbp
movq %rbp, %rdi
movq %r13, %rcx
callq 0x3ac8
movq %rbp, %rdi
leaq 0x40(%rsp), %rsi
callq 0x3c06
testl %eax, %eax
jne 0x4855
movq %r12, %rdi
movl 0x18(%rsp), %ecx
movq 0x28(%rsp), %r8
movq 0x10(%rsp), %r9
callq 0x392c
testb %al, %al
je 0x483f
incq 0x8(%rsp)
movq %r12, %rdi
movq %r15, %rsi
movq %r14, %rdx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x3c72
movq %r12, %rdi
callq 0x570e
incq %r14
cmpq %rbx, %r14
jbe 0x4784
jmp 0x48c2
movl %eax, %ebp
movl $0xf, 0x78db(%rip)      # 0xc13c
incq 0x20(%rsp)
je 0x4872
movl $0xa, %edi
callq 0x3040
movq (%r12), %rcx
leaq 0x1e42(%rip), %rdi      # 0x66bf
movq 0x20(%rsp), %rsi
movq %r14, %rdx
xorl %eax, %eax
callq 0x30d0
movl %ebp, %edi
movq %r15, %rsi
movq %r14, %rdx
callq 0x3f62
movq (%r12), %rsi
leaq 0x38(%rsp), %rdi
callq 0x435f
movq %r12, %rdi
callq 0x570e
incq %r14
cmpq %rbx, %r14
movq 0x8(%rsp), %rax
jbe 0x477f
jmp 0x48e0
cmpb $0x0, (%rsp)
movq 0x8(%rsp), %rsi
je 0x48e0
leaq 0x1e70(%rip), %rdi      # 0x6744
xorl %eax, %eax
callq 0x30d0
jmp 0x4997
leaq 0x1e00(%rip), %rdi      # 0x66e7
movq 0x20(%rsp), %rbx
movq %rbx, %rsi
xorl %eax, %eax
callq 0x30d0
testq %rbx, %rbx
je 0x494f
leaq 0x3097(%rip), %rdi      # 0x7999
callq 0x3080
movq 0x38(%rsp), %rbx
testq %rbx, %rbx
je 0x494f
leaq 0x1e02(%rip), %r14      # 0x671a
movq 0x8(%rbx), %rsi
movq 0x10(%rbx), %rdx
movq %r14, %rdi
xorl %eax, %eax
callq 0x30d0
movq (%rbx), %r12
movq %rbx, %rdi
callq 0x3030
movq %r12, %rbx
testq %r12, %r12
jne 0x4918
jmp 0x494f
leaq 0x1da1(%rip), %rdi      # 0x66e7
xorl %esi, %esi
xorl %eax, %eax
callq 0x30d0
movl $0x1, %ebx
movq 0x40(%rsp), %rdi
movq 0x20(%rdi), %r14
callq 0x3aa7
movl %ebx, %eax
incl %ebx
movq %r14, %rdi
cmpq %rax, %r13
ja 0x4959
movq 0x70(%rsp), %rbx
testq %rbx, %rbx
je 0x4997
movl $0x1, %ebp
movq 0x60(%rsp), %rdi
movq 0x20(%rdi), %r14
callq 0x3aa7
movl %ebp, %eax
incl %ebp
movq %r14, %rdi
cmpq %rax, %rbx
ja 0x4982
movq %r15, %rdi
callq 0x546d
xorl %eax, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x3491
callq 0x34b6
movq %r15, %rdi
callq 0x3480
movq %r15, %rdi
callq 0x34db
callq 0x3508
nop