// File: /workspace/github_c_makefile_star2_O2/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 $0x88, %rsp
movq %rsi, %r13
movl %edi, %r14d
andq $0x0, 0x7260(%rip)      # 0xb148
andq $0x0, 0x7260(%rip)      # 0xb150
movq $0x0, 0x28(%rsp)
pushq $-0x1
popq %rbp
pushq $0x1
popq %rax
leaq 0x2661(%rip), %rbx      # 0x6567
leaq 0x2123(%rip), %r15      # 0x6030
movq $0x0, 0x30(%rsp)
movq $0x0, 0x20(%rsp)
movl $0x0, 0xc(%rsp)
movq %rax, 0x18(%rsp)
movl %eax, 0x10(%rsp)
movl %r14d, %edi
movq %r13, %rsi
movq %rbx, %rdx
callq 0x3200
leal -0x65(%rax), %ecx
cmpl $0xe, %ecx
ja 0x3f6b
movslq (%r15,%rcx,4), %rax
addq %r15, %rax
jmpq *%rax
movq 0x7082(%rip), %rax      # 0xafd8
movq (%rax), %rdi
callq 0x3210
movl %eax, 0xc(%rsp)
testl %eax, %eax
jg 0x3f30
jmp 0x43eb
cmpl $0x61, %eax
je 0x3fcf
cmpl $0x79, %eax
je 0x4046
cmpl $-0x1, %eax
jne 0x3f30
jmp 0x4075
movq 0x704e(%rip), %rax      # 0xafd8
movq (%rax), %rdi
callq 0x3210
movl %eax, 0x10(%rsp)
testl %eax, %eax
jne 0x3f30
jmp 0x4400
movb $0x1, 0x7192(%rip)      # 0xb138
jmp 0x3f30
movb $0x1, 0x718a(%rip)      # 0xb139
jmp 0x3f30
movq 0x701d(%rip), %rax      # 0xafd8
movq (%rax), %rax
movq %rax, 0x68(%rsp)
movb $0x1, %al
movq %rax, 0x20(%rsp)
jmp 0x3f30
movq 0x7002(%rip), %rax      # 0xafd8
movq (%rax), %rbp
movq %rbp, %rdi
pushq $0x2c
popq %rsi
callq 0x3100
movq %rax, %r12
cmpb $0x30, (%rbp)
jne 0x3ffb
xorl %eax, %eax
cmpb $0x78, 0x1(%rbp)
sete %al
leaq (%rbp,%rax,2), %rbp
movq %rbp, %rdi
xorl %esi, %esi
pushq $0x10
popq %rdx
callq 0x3190
movq %rax, %rbp
testq %r12, %r12
je 0x3f30
cmpb $0x30, 0x1(%r12)
jne 0x4052
cmpb $0x78, 0x2(%r12)
jne 0x4052
addq $0x3, %r12
movq %r12, %rdi
xorl %esi, %esi
pushq $0x10
popq %rdx
callq 0x3190
movq %rax, 0x18(%rsp)
movb $0x1, %al
movq %rax, 0x28(%rsp)
jmp 0x3f30
movb $0x1, %al
movq %rax, 0x30(%rsp)
jmp 0x3f30
incq %r12
movq $0x0, 0x28(%rsp)
movq %r12, %rdi
xorl %esi, %esi
pushq $0xa
popq %rdx
callq 0x3190
movq %rax, 0x18(%rsp)
jmp 0x3f30
movq 0x6f54(%rip), %rax      # 0xafd0
cmpl %r14d, (%rax)
jge 0x4424
movq 0x6f6c(%rip), %r15      # 0xaff8
movq (%r15), %rdi
leaq 0x35ef(%rip), %rsi      # 0x7685
pushq $0x4
popq %rdx
xorl %eax, %eax
callq 0x3160
cmpq $-0x1, %rbp
movq 0x20(%rsp), %r12
je 0x40f9
cmpl $0x2, 0x18(%rsp)
jb 0x40d3
leaq 0x254b(%rip), %rdi      # 0x6604
movq %rbp, %rsi
xorl %eax, %eax
callq 0x30d0
testb $0x1, 0x28(%rsp)
je 0x40e6
leaq 0x256d(%rip), %rdi      # 0x663e
jmp 0x40ed
leaq 0x257c(%rip), %rdi      # 0x6656
movq %rbp, %rsi
xorl %eax, %eax
callq 0x30d0
jmp 0x40f9
leaq 0x255e(%rip), %rdi      # 0x664b
movq 0x18(%rsp), %rsi
xorl %eax, %eax
callq 0x30d0
movslq %r14d, %rax
movq -0x8(%r13,%rax,8), %rbx
pushq $0x40
popq %rdi
callq 0x31b0
testq %rax, %rax
je 0x4442
movq %rax, %r13
movq %rbx, %rdi
movq %rax, %rsi
callq 0x4c2a
movq %r13, %rdi
callq 0x48bc
movq %rax, %rbx
movq %rax, %xmm1
punpckldq 0x1ed8(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x1ee0(%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, 0x6fe3(%rip)       # 0xb140
xorpd %xmm0, %xmm0
movapd %xmm0, 0x40(%rsp)
andq $0x0, 0x50(%rsp)
testb $0x1, %r12b
movq %rbp, 0x60(%rsp)
je 0x419f
leaq 0x40(%rsp), %r14
movq %r14, %rdi
movq 0x68(%rsp), %rsi
callq 0x3aef
movq 0x10(%r14), %r14
testq %r14, %r14
je 0x41ac
leaq 0x40(%rsp), %rdi
callq 0x3c66
jmp 0x41af
xorl %r14d, %r14d
movl 0x10(%rsp), %eax
movl 0xc(%rsp), %ecx
jmp 0x41bb
xorl %r14d, %r14d
movl 0x10(%rsp), %eax
movl 0xc(%rsp), %ecx
xorpd %xmm0, %xmm0
leaq 0x70(%rsp), %rdx
andq $0x0, 0x10(%rdx)
leaq 0x38(%rsp), %rsi
andq $0x0, (%rsi)
movapd %xmm0, (%rdx)
testl %ecx, %ecx
movl %ecx, %r15d
cmoveq %rbx, %r15
testl %eax, %eax
cltq
leaq 0x1(%rax,%r15), %rcx
movl %eax, %ebp
cmovsq %rcx, %rbp
leaq 0x24a7(%rip), %rdi      # 0x6698
movq %rbp, %rsi
movq %r15, %rdx
movq %rbx, %rcx
xorl %eax, %eax
callq 0x30d0
movzbl %r12b, %eax
andl $0x1, %eax
movl %eax, 0xc(%rsp)
movq $0x0, 0x20(%rsp)
xorl %r12d, %r12d
movq %r14, 0x10(%rsp)
cmpq %r15, %rbp
ja 0x4339
movq %rbp, %rdi
movq %r13, %rsi
callq 0x5074
movq %rax, %rbx
testb $0x1, 0x30(%rsp)
je 0x4274
cmpq $0x2, 0x8(%rbx)
jne 0x4267
cmpb $0xf, 0x10(%rbx)
jne 0x4267
cmpb $0x5, 0x11(%rbx)
jne 0x4267
movq %rbx, %rdi
movq %r13, %rsi
movq %rbp, %rdx
xorl %ecx, %ecx
pushq $0x1
popq %r8
callq 0x366e
incq 0x20(%rsp)
movq %rbx, %rdi
callq 0x52ab
jmp 0x4331
testq %r14, %r14
je 0x42f2
movq %r14, %rcx
movq %rbx, %rsi
addq $0x10, %rsi
movl 0x8(%rbx), %edx
leaq 0x70(%rsp), %r14
movq %r14, %rdi
callq 0x34bc
movq %r14, %rdi
leaq 0x40(%rsp), %rsi
callq 0x3606
testl %eax, %eax
je 0x42f2
movl %eax, %r14d
movl $0xf, 0x6e8b(%rip)      # 0xb13c
incq %r12
je 0x42be
pushq $0xa
popq %rdi
callq 0x3040
movq (%rbx), %rcx
leaq 0x23f7(%rip), %rdi      # 0x66bf
movq %r12, %rsi
movq %rbp, %rdx
xorl %eax, %eax
callq 0x30d0
movl %r14d, %edi
movq %r13, %rsi
movq %rbp, %rdx
callq 0x3945
movq (%rbx), %rsi
leaq 0x38(%rsp), %rdi
callq 0x3e30
jmp 0x4324
movq %rbx, %rdi
movl 0xc(%rsp), %ecx
movq 0x60(%rsp), %r8
movq 0x18(%rsp), %r9
callq 0x333c
testb %al, %al
je 0x4324
incq 0x20(%rsp)
movq %rbx, %rdi
movq %r13, %rsi
movq %rbp, %rdx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x366e
movq %rbx, %rdi
callq 0x52ab
movq 0x10(%rsp), %r14
incq %rbp
jmp 0x421d
testq %r14, %r14
je 0x43b1
leaq 0x23a2(%rip), %rdi      # 0x66e7
movq %r12, %rsi
xorl %eax, %eax
callq 0x30d0
testq %r12, %r12
je 0x439b
leaq 0x363e(%rip), %rdi      # 0x7999
callq 0x3080
movq 0x38(%rsp), %r14
leaq 0x23ae(%rip), %rbx      # 0x671a
testq %r14, %r14
je 0x4393
movq 0x8(%r14), %rsi
movq 0x10(%r14), %rdx
movq %rbx, %rdi
xorl %eax, %eax
callq 0x30d0
movq (%r14), %r15
movq %r14, %rdi
callq 0x3030
movq %r15, %r14
jmp 0x436c
cmpq $0x0, 0x10(%rsp)
je 0x43c4
leaq 0x40(%rsp), %rdi
callq 0x3c38
leaq 0x70(%rsp), %rdi
callq 0x3c38
jmp 0x43c4
leaq 0x238c(%rip), %rdi      # 0x6744
movq 0x20(%rsp), %rsi
xorl %eax, %eax
callq 0x30d0
movq %r13, %rdi
callq 0x4fcb
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq (%r13), %rdi
callq 0x3d4a
jmp 0x441c
movq 0x6c06(%rip), %rax      # 0xaff8
movq (%rax), %rcx
leaq 0x21b2(%rip), %rdi      # 0x65ae
pushq $0x21
jmp 0x4413
movq 0x6bf1(%rip), %rax      # 0xaff8
movq (%rax), %rcx
leaq 0x2163(%rip), %rdi      # 0x6574
pushq $0x39
popq %rsi
pushq $0x1
popq %rdx
callq 0x3230
pushq $0x1
popq %rdi
callq 0x3220
movq (%r13), %rdi
callq 0x3d4a
movq 0x6bc4(%rip), %rax      # 0xaff8
movq (%rax), %rcx
leaq 0x2192(%rip), %rdi      # 0x65d0
pushq $0x33
jmp 0x4413
movq (%r15), %rcx
leaq 0x222c(%rip), %rdi      # 0x6678
pushq $0x1f
jmp 0x4413