// File: /workspace/github_c_makefile_star2_O1/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, 0x7d70(%rip)      # 0xc140
movq $0x0, (%rsp)
movq %rax, 0x7d69(%rip)      # 0xc148
movq $-0x1, %rbp
movl $0x1, %eax
movq %rax, 0x10(%rsp)
leaq 0x2170(%rip), %rbx      # 0x6567
leaq 0x1c32(%rip), %r12      # 0x6030
movq $0x0, 0x30(%rsp)
movq $0x0, 0x28(%rsp)
movl $0x0, 0x24(%rsp)
movl $0x1, 0x8(%rsp)
movl %r14d, %edi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x31f0
cmpl $0x64, %eax
jle 0x4464
leal -0x65(%rax), %ecx
cmpl $0xe, %ecx
ja 0x44ef
movslq (%r12,%rcx,4), %rax
addq %r12, %rax
jmpq *%rax
movq 0x7b89(%rip), %rax      # 0xbfd8
movq (%rax), %rdi
callq 0x3200
movl %eax, 0x24(%rsp)
testl %eax, %eax
jg 0x4420
jmp 0x4950
cmpl $0x61, %eax
jne 0x4557
movq 0x7b64(%rip), %rax      # 0xbfd8
movq (%rax), %rbp
movq %rbp, %rdi
movl $0x2c, %esi
callq 0x3100
movq %rax, %r13
cmpb $0x30, (%rbp)
jne 0x449b
xorl %eax, %eax
cmpb $0x78, 0x1(%rbp)
sete %al
leaq (%rbp,%rax,2), %rbp
movq %rbp, %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x3180
movq %rax, %rbp
testq %r13, %r13
je 0x4420
cmpb $0x30, 0x1(%r13)
jne 0x4562
cmpb $0x78, 0x2(%r13)
jne 0x4562
addq $0x3, %r13
movq %r13, %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x3180
movq %rax, 0x10(%rsp)
movb $0x1, %al
movq %rax, (%rsp)
jmp 0x4420
cmpl $0x79, %eax
jne 0x4420
movb $0x1, %al
movq %rax, 0x30(%rsp)
jmp 0x4420
movq 0x7acd(%rip), %rax      # 0xbfd8
movq (%rax), %rax
movq %rax, 0x18(%rsp)
movb $0x1, %al
movq %rax, 0x28(%rsp)
jmp 0x4420
movq 0x7ab2(%rip), %rax      # 0xbfd8
movq (%rax), %rdi
callq 0x3200
movl %eax, 0x8(%rsp)
testl %eax, %eax
jne 0x4420
jmp 0x4955
movb $0x1, 0x7bea(%rip)      # 0xc130
jmp 0x4420
movb $0x1, 0x7bdf(%rip)      # 0xc131
jmp 0x4420
cmpl $-0x1, %eax
jne 0x4420
jmp 0x4586
incq %r13
movq $0x0, (%rsp)
movq %r13, %rdi
xorl %esi, %esi
movl $0xa, %edx
callq 0x3180
movq %rax, 0x10(%rsp)
jmp 0x4420
movq 0x7a43(%rip), %rax      # 0xbfd0
cmpl %r14d, (%rax)
jge 0x4962
movq 0x7a5b(%rip), %rax      # 0xbff8
movq (%rax), %rdi
leaq 0x30de(%rip), %rsi      # 0x7685
movl $0x4, %edx
xorl %eax, %eax
callq 0x3150
cmpq $-0x1, %rbp
je 0x4606
cmpl $0x2, 0x10(%rsp)
jb 0x45e0
leaq 0x203d(%rip), %rdi      # 0x6604
movq %rbp, %rsi
xorl %eax, %eax
callq 0x30d0
testb $0x1, (%rsp)
je 0x45f3
leaq 0x2060(%rip), %rdi      # 0x663e
jmp 0x45fa
leaq 0x206f(%rip), %rdi      # 0x6656
movq %rbp, %rsi
xorl %eax, %eax
callq 0x30d0
jmp 0x4606
leaq 0x2051(%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 0x31a0
testq %rax, %rax
movq 0x18(%rsp), %r12
je 0x496a
movq %rax, %r14
movq %rbx, %rdi
movq %rax, %rsi
callq 0x50f6
movq %r14, (%rsp)
movq %r14, %rdi
callq 0x4db3
movq %rax, %rbx
movq %rax, %xmm1
punpckldq 0x19c0(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x19c8(%rip), %xmm1     # 0x6020
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
callq 0x3140
cvttsd2si %xmm0, %eax
addb $0x2, %al
movb %al, 0x7ac3(%rip)       # 0xc138
xorpd %xmm0, %xmm0
movapd %xmm0, 0x40(%rsp)
movq $0x0, 0x50(%rsp)
movq 0x28(%rsp), %r15
testb $0x1, %r15b
je 0x46a0
leaq 0x40(%rsp), %rdi
movq %r12, %rsi
callq 0x40f4
movq 0x50(%rsp), %r14
testq %r14, %r14
je 0x46b4
leaq 0x40(%rsp), %rdi
callq 0x4241
xorpd %xmm0, %xmm0
movapd %xmm0, 0x60(%rsp)
xorl %eax, %eax
movq %rax, 0x70(%rsp)
movq $0x0, 0x18(%rsp)
movq %rax, 0x38(%rsp)
movl 0x24(%rsp), %eax
testl %eax, %eax
movl %eax, %r12d
cmoveq %rbx, %r12
movl 0x8(%rsp), %eax
testl %eax, %eax
cltq
leaq 0x1(%rax,%r12), %rcx
movl %eax, %r13d
cmovsq %rcx, %r13
leaq 0x1f9d(%rip), %rdi      # 0x6698
movq %r13, %rsi
movq %r12, %rdx
movq %rbx, %rcx
xorl %eax, %eax
callq 0x30d0
movl $0x0, %eax
movq %rax, 0x8(%rsp)
cmpq %r12, %r13
ja 0x486f
movzbl %r15b, %eax
andl $0x1, %eax
movl %eax, 0x28(%rsp)
movq $0x0, 0x8(%rsp)
movq $0x0, 0x18(%rsp)
movq %r13, %rdi
movq (%rsp), %r15
movq %r15, %rsi
callq 0x54e5
movq %rax, %rbx
testb $0x1, 0x30(%rsp)
je 0x4793
cmpq $0x2, 0x8(%rbx)
jne 0x485b
cmpb $0xf, 0x10(%rbx)
jne 0x485b
cmpb $0x5, 0x11(%rbx)
jne 0x485b
movq %rbx, %rdi
movq %r15, %rsi
movq %r13, %rdx
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x3c53
incq 0x18(%rsp)
jmp 0x485b
testq %r14, %r14
je 0x482a
movq %rbp, %r15
movq %rbx, %rsi
addq $0x10, %rsi
movl 0x8(%rbx), %edx
leaq 0x60(%rsp), %rbp
movq %rbp, %rdi
movq %r14, %rcx
callq 0x3ab9
movq %rbp, %rdi
leaq 0x40(%rsp), %rsi
callq 0x3be0
movl %eax, %ebp
testl %eax, %eax
je 0x4823
movl $0xf, 0x795e(%rip)      # 0xc134
incq 0x8(%rsp)
je 0x47e7
movl $0xa, %edi
callq 0x3040
movq (%rbx), %rcx
leaq 0x1ece(%rip), %rdi      # 0x66bf
movq 0x8(%rsp), %rsi
movq %r13, %rdx
xorl %eax, %eax
callq 0x30d0
movl %ebp, %edi
movq (%rsp), %rsi
movq %r13, %rdx
callq 0x3f4f
movq (%rbx), %rsi
leaq 0x38(%rsp), %rdi
callq 0x432c
movq %rbx, %rdi
callq 0x56dc
testl %ebp, %ebp
movq %r15, %rbp
jne 0x4863
movq %rbx, %rdi
movl 0x28(%rsp), %ecx
movq %rbp, %r8
movq 0x10(%rsp), %r9
callq 0x391c
testb %al, %al
je 0x485b
incq 0x18(%rsp)
movq %rbx, %rdi
movq (%rsp), %rsi
movq %r13, %rdx
xorl %ecx, %ecx
xorl %r8d, %r8d
callq 0x3c53
movq %rbx, %rdi
callq 0x56dc
incq %r13
cmpq %r12, %r13
jbe 0x473b
testq %r14, %r14
je 0x48d3
leaq 0x1e6c(%rip), %rdi      # 0x66e7
movq 0x8(%rsp), %rbx
movq %rbx, %rsi
xorl %eax, %eax
callq 0x30d0
testq %rbx, %rbx
je 0x48e6
leaq 0x3103(%rip), %rdi      # 0x7999
callq 0x3080
movq 0x38(%rsp), %rbx
testq %rbx, %rbx
je 0x48e6
leaq 0x1e6e(%rip), %r12      # 0x671a
movq 0x8(%rbx), %rsi
movq 0x10(%rbx), %rdx
movq %r12, %rdi
xorl %eax, %eax
callq 0x30d0
movq (%rbx), %r13
movq %rbx, %rdi
callq 0x3030
movq %r13, %rbx
testq %r13, %r13
jne 0x48ac
jmp 0x48e6
leaq 0x1e6a(%rip), %rdi      # 0x6744
movq 0x18(%rsp), %rsi
xorl %eax, %eax
callq 0x30d0
testq %r14, %r14
movq (%rsp), %r15
je 0x4937
movl $0x1, %ebx
movq 0x40(%rsp), %rdi
movq 0x20(%rdi), %r12
callq 0x3a98
movl %ebx, %eax
incl %ebx
movq %r12, %rdi
cmpq %rax, %r14
ja 0x48f9
movq 0x70(%rsp), %rbx
testq %rbx, %rbx
je 0x4937
movl $0x1, %ebp
movq 0x60(%rsp), %rdi
movq 0x20(%rdi), %r14
callq 0x3a98
movl %ebp, %eax
incl %ebp
movq %r14, %rdi
cmpq %rax, %rbx
ja 0x4922
movq %r15, %rdi
callq 0x5438
xorl %eax, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x3481
callq 0x34a6
movq %r15, %rdi
callq 0x3470
movq %r15, %rdi
callq 0x34cb
callq 0x34f8
nop